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 editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlays;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39mod split;
   40pub mod split_editor_view;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction_types::Direction;
   56pub use editor_settings::{
   57    CompletionDetailAlignment, CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings,
   58    HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   59};
   60pub use element::{
   61    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, OverlayPainter,
   62    OverlayPainterData, PointForPosition, render_breadcrumb_text,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use inlays::Inlay;
   67pub use items::MAX_TAB_TITLE_LEN;
   68pub use lsp::CompletionContext;
   69pub use lsp_ext::lsp_tasks;
   70pub use multi_buffer::{
   71    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   72    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   73    ToPoint,
   74};
   75pub use split::{SplittableEditor, ToggleLockedCursors, ToggleSplitDiff};
   76pub use split_editor_view::SplitEditorView;
   77pub use text::Bias;
   78
   79use ::git::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus};
   80use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   81use anyhow::{Context as _, Result, anyhow, bail};
   82use blink_manager::BlinkManager;
   83use buffer_diff::DiffHunkStatus;
   84use client::{Collaborator, ParticipantIndex, parse_zed_link};
   85use clock::ReplicaId;
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   91use convert_case::{Case, Casing};
   92use dap::TelemetrySpawnLocation;
   93use display_map::*;
   94use edit_prediction_types::{
   95    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionGranularity,
   96    SuggestionDisplayType,
   97};
   98use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   99use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
  100use futures::{
  101    FutureExt,
  102    future::{self, Shared, join},
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontStyle, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage,
  112    Render, ScrollHandle, SharedString, SharedUri, Size, Stateful, Styled, Subscription, Task,
  113    TextRun, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle,
  114    UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window, div, point, prelude::*,
  115    pulsating_between, px, relative, size,
  116};
  117use hover_links::{HoverLink, HoveredLinkState, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  125    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  126    IndentSize, Language, LanguageName, LanguageRegistry, LanguageScope, OffsetRangeExt,
  127    OutlineItem, Point, Runnable, Selection, SelectionGoal, TextObject, TransactionId,
  128    TreeSitterOptions, WordsQuery,
  129    language_settings::{
  130        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  131        all_language_settings, language_settings,
  132    },
  133    point_from_lsp, point_to_lsp, text_diff_with_options,
  134};
  135use linked_editing_ranges::refresh_linked_ranges;
  136use lsp::{
  137    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  138    LanguageServerId,
  139};
  140use lsp_colors::LspColorData;
  141use markdown::Markdown;
  142use mouse_context_menu::MouseContextMenu;
  143use movement::TextLayoutDetails;
  144use multi_buffer::{
  145    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  152    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  153    ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::GitStoreEvent,
  162    lsp_store::{
  163        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  164        OpenLspBufferHandle,
  165    },
  166    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  167};
  168use rand::seq::SliceRandom;
  169use regex::Regex;
  170use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  171use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  172use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  173use serde::{Deserialize, Serialize};
  174use settings::{
  175    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  176    update_settings_file,
  177};
  178use smallvec::{SmallVec, smallvec};
  179use snippet::Snippet;
  180use std::{
  181    any::{Any, TypeId},
  182    borrow::Cow,
  183    cell::{OnceCell, RefCell},
  184    cmp::{self, Ordering, Reverse},
  185    collections::hash_map,
  186    iter::{self, Peekable},
  187    mem,
  188    num::NonZeroU32,
  189    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  190    path::{Path, PathBuf},
  191    rc::Rc,
  192    sync::Arc,
  193    time::{Duration, Instant},
  194};
  195use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  196use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  197use theme::{
  198    AccentColors, ActiveTheme, GlobalTheme, PlayerColor, StatusColors, SyntaxTheme, Theme,
  199    ThemeSettings, observe_buffer_font_size_adjustment,
  200};
  201use ui::{
  202    Avatar, ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape,
  203    IconName, IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  204};
  205use ui_input::ErasedEditor;
  206use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  207use workspace::{
  208    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, NavigationEntry, OpenInTerminal,
  209    OpenTerminal, Pane, RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection,
  210    TabBarSettings, Toast, ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  211    item::{BreadcrumbText, ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  212    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  213    searchable::{CollapseDirection, SearchEvent},
  214};
  215use zed_actions::editor::{MoveDown, MoveUp};
  216
  217use crate::{
  218    code_context_menus::CompletionsMenuSource,
  219    editor_settings::MultiCursorModifier,
  220    hover_links::{find_url, find_url_from_range},
  221    inlays::{
  222        InlineValueCache,
  223        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  224    },
  225    scroll::{ScrollOffset, ScrollPixelOffset},
  226    selections_collection::resolve_selections_wrapping_blocks,
  227    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  228};
  229
  230pub const FILE_HEADER_HEIGHT: u32 = 2;
  231pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  232const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  233const MAX_LINE_LEN: usize = 1024;
  234const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  235const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  236pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  237#[doc(hidden)]
  238pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  239pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  240
  241pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  242pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  243pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  244pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  245
  246pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  247pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  248pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  249
  250pub type RenderDiffHunkControlsFn = Arc<
  251    dyn Fn(
  252        u32,
  253        &DiffHunkStatus,
  254        Range<Anchor>,
  255        bool,
  256        Pixels,
  257        &Entity<Editor>,
  258        &mut Window,
  259        &mut App,
  260    ) -> AnyElement,
  261>;
  262
  263enum ReportEditorEvent {
  264    Saved { auto_saved: bool },
  265    EditorOpened,
  266    Closed,
  267}
  268
  269impl ReportEditorEvent {
  270    pub fn event_type(&self) -> &'static str {
  271        match self {
  272            Self::Saved { .. } => "Editor Saved",
  273            Self::EditorOpened => "Editor Opened",
  274            Self::Closed => "Editor Closed",
  275        }
  276    }
  277}
  278
  279pub enum ActiveDebugLine {}
  280pub enum DebugStackFrameLine {}
  281enum DocumentHighlightRead {}
  282enum DocumentHighlightWrite {}
  283enum InputComposition {}
  284pub enum PendingInput {}
  285enum SelectedTextHighlight {}
  286
  287pub enum ConflictsOuter {}
  288pub enum ConflictsOurs {}
  289pub enum ConflictsTheirs {}
  290pub enum ConflictsOursMarker {}
  291pub enum ConflictsTheirsMarker {}
  292
  293pub struct HunkAddedColor;
  294pub struct HunkRemovedColor;
  295
  296#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  297pub enum Navigated {
  298    Yes,
  299    No,
  300}
  301
  302impl Navigated {
  303    pub fn from_bool(yes: bool) -> Navigated {
  304        if yes { Navigated::Yes } else { Navigated::No }
  305    }
  306}
  307
  308#[derive(Debug, Clone, PartialEq, Eq)]
  309enum DisplayDiffHunk {
  310    Folded {
  311        display_row: DisplayRow,
  312    },
  313    Unfolded {
  314        is_created_file: bool,
  315        diff_base_byte_range: Range<usize>,
  316        display_row_range: Range<DisplayRow>,
  317        multi_buffer_range: Range<Anchor>,
  318        status: DiffHunkStatus,
  319        word_diffs: Vec<Range<MultiBufferOffset>>,
  320    },
  321}
  322
  323pub enum HideMouseCursorOrigin {
  324    TypingAction,
  325    MovementAction,
  326}
  327
  328pub fn init(cx: &mut App) {
  329    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  330
  331    workspace::register_project_item::<Editor>(cx);
  332    workspace::FollowableViewRegistry::register::<Editor>(cx);
  333    workspace::register_serializable_item::<Editor>(cx);
  334
  335    cx.observe_new(
  336        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  337            workspace.register_action(Editor::new_file);
  338            workspace.register_action(Editor::new_file_split);
  339            workspace.register_action(Editor::new_file_vertical);
  340            workspace.register_action(Editor::new_file_horizontal);
  341            workspace.register_action(Editor::cancel_language_server_work);
  342            workspace.register_action(Editor::toggle_focus);
  343        },
  344    )
  345    .detach();
  346
  347    cx.on_action(move |_: &workspace::NewFile, cx| {
  348        let app_state = workspace::AppState::global(cx);
  349        if let Some(app_state) = app_state.upgrade() {
  350            workspace::open_new(
  351                Default::default(),
  352                app_state,
  353                cx,
  354                |workspace, window, cx| {
  355                    Editor::new_file(workspace, &Default::default(), window, cx)
  356                },
  357            )
  358            .detach();
  359        }
  360    })
  361    .on_action(move |_: &workspace::NewWindow, cx| {
  362        let app_state = workspace::AppState::global(cx);
  363        if let Some(app_state) = app_state.upgrade() {
  364            workspace::open_new(
  365                Default::default(),
  366                app_state,
  367                cx,
  368                |workspace, window, cx| {
  369                    cx.activate(true);
  370                    Editor::new_file(workspace, &Default::default(), window, cx)
  371                },
  372            )
  373            .detach();
  374        }
  375    });
  376    _ = ui_input::ERASED_EDITOR_FACTORY.set(|window, cx| {
  377        Arc::new(ErasedEditorImpl(
  378            cx.new(|cx| Editor::single_line(window, cx)),
  379        )) as Arc<dyn ErasedEditor>
  380    });
  381    _ = multi_buffer::EXCERPT_CONTEXT_LINES.set(multibuffer_context_lines);
  382}
  383
  384pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  385    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  386}
  387
  388pub trait DiagnosticRenderer {
  389    fn render_group(
  390        &self,
  391        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  392        buffer_id: BufferId,
  393        snapshot: EditorSnapshot,
  394        editor: WeakEntity<Editor>,
  395        language_registry: Option<Arc<LanguageRegistry>>,
  396        cx: &mut App,
  397    ) -> Vec<BlockProperties<Anchor>>;
  398
  399    fn render_hover(
  400        &self,
  401        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  402        range: Range<Point>,
  403        buffer_id: BufferId,
  404        language_registry: Option<Arc<LanguageRegistry>>,
  405        cx: &mut App,
  406    ) -> Option<Entity<markdown::Markdown>>;
  407
  408    fn open_link(
  409        &self,
  410        editor: &mut Editor,
  411        link: SharedString,
  412        window: &mut Window,
  413        cx: &mut Context<Editor>,
  414    );
  415}
  416
  417pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  418
  419impl GlobalDiagnosticRenderer {
  420    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  421        cx.try_global::<Self>().map(|g| g.0.clone())
  422    }
  423}
  424
  425impl gpui::Global for GlobalDiagnosticRenderer {}
  426pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  427    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  428}
  429
  430pub struct SearchWithinRange;
  431
  432trait InvalidationRegion {
  433    fn ranges(&self) -> &[Range<Anchor>];
  434}
  435
  436#[derive(Clone, Debug, PartialEq)]
  437pub enum SelectPhase {
  438    Begin {
  439        position: DisplayPoint,
  440        add: bool,
  441        click_count: usize,
  442    },
  443    BeginColumnar {
  444        position: DisplayPoint,
  445        reset: bool,
  446        mode: ColumnarMode,
  447        goal_column: u32,
  448    },
  449    Extend {
  450        position: DisplayPoint,
  451        click_count: usize,
  452    },
  453    Update {
  454        position: DisplayPoint,
  455        goal_column: u32,
  456        scroll_delta: gpui::Point<f32>,
  457    },
  458    End,
  459}
  460
  461#[derive(Clone, Debug, PartialEq)]
  462pub enum ColumnarMode {
  463    FromMouse,
  464    FromSelection,
  465}
  466
  467#[derive(Clone, Debug)]
  468pub enum SelectMode {
  469    Character,
  470    Word(Range<Anchor>),
  471    Line(Range<Anchor>),
  472    All,
  473}
  474
  475#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  476pub enum SizingBehavior {
  477    /// The editor will layout itself using `size_full` and will include the vertical
  478    /// scroll margin as requested by user settings.
  479    #[default]
  480    Default,
  481    /// The editor will layout itself using `size_full`, but will not have any
  482    /// vertical overscroll.
  483    ExcludeOverscrollMargin,
  484    /// The editor will request a vertical size according to its content and will be
  485    /// layouted without a vertical scroll margin.
  486    SizeByContent,
  487}
  488
  489#[derive(Clone, PartialEq, Eq, Debug)]
  490pub enum EditorMode {
  491    SingleLine,
  492    AutoHeight {
  493        min_lines: usize,
  494        max_lines: Option<usize>,
  495    },
  496    Full {
  497        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  498        scale_ui_elements_with_buffer_font_size: bool,
  499        /// When set to `true`, the editor will render a background for the active line.
  500        show_active_line_background: bool,
  501        /// Determines the sizing behavior for this editor
  502        sizing_behavior: SizingBehavior,
  503    },
  504    Minimap {
  505        parent: WeakEntity<Editor>,
  506    },
  507}
  508
  509impl EditorMode {
  510    pub fn full() -> Self {
  511        Self::Full {
  512            scale_ui_elements_with_buffer_font_size: true,
  513            show_active_line_background: true,
  514            sizing_behavior: SizingBehavior::Default,
  515        }
  516    }
  517
  518    #[inline]
  519    pub fn is_full(&self) -> bool {
  520        matches!(self, Self::Full { .. })
  521    }
  522
  523    #[inline]
  524    pub fn is_single_line(&self) -> bool {
  525        matches!(self, Self::SingleLine { .. })
  526    }
  527
  528    #[inline]
  529    fn is_minimap(&self) -> bool {
  530        matches!(self, Self::Minimap { .. })
  531    }
  532}
  533
  534#[derive(Copy, Clone, Debug)]
  535pub enum SoftWrap {
  536    /// Prefer not to wrap at all.
  537    ///
  538    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  539    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  540    GitDiff,
  541    /// Prefer a single line generally, unless an overly long line is encountered.
  542    None,
  543    /// Soft wrap lines that exceed the editor width.
  544    EditorWidth,
  545    /// Soft wrap lines at the preferred line length.
  546    Column(u32),
  547    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  548    Bounded(u32),
  549}
  550
  551#[derive(Clone)]
  552pub struct EditorStyle {
  553    pub background: Hsla,
  554    pub border: Hsla,
  555    pub local_player: PlayerColor,
  556    pub text: TextStyle,
  557    pub scrollbar_width: Pixels,
  558    pub syntax: Arc<SyntaxTheme>,
  559    pub status: StatusColors,
  560    pub inlay_hints_style: HighlightStyle,
  561    pub edit_prediction_styles: EditPredictionStyles,
  562    pub unnecessary_code_fade: f32,
  563    pub show_underlines: bool,
  564}
  565
  566impl Default for EditorStyle {
  567    fn default() -> Self {
  568        Self {
  569            background: Hsla::default(),
  570            border: Hsla::default(),
  571            local_player: PlayerColor::default(),
  572            text: TextStyle::default(),
  573            scrollbar_width: Pixels::default(),
  574            syntax: Default::default(),
  575            // HACK: Status colors don't have a real default.
  576            // We should look into removing the status colors from the editor
  577            // style and retrieve them directly from the theme.
  578            status: StatusColors::dark(),
  579            inlay_hints_style: HighlightStyle::default(),
  580            edit_prediction_styles: EditPredictionStyles {
  581                insertion: HighlightStyle::default(),
  582                whitespace: HighlightStyle::default(),
  583            },
  584            unnecessary_code_fade: Default::default(),
  585            show_underlines: true,
  586        }
  587    }
  588}
  589
  590pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  591    let show_background = language_settings::language_settings(None, None, cx)
  592        .inlay_hints
  593        .show_background;
  594
  595    let mut style = cx.theme().syntax().get("hint");
  596
  597    if style.color.is_none() {
  598        style.color = Some(cx.theme().status().hint);
  599    }
  600
  601    if !show_background {
  602        style.background_color = None;
  603        return style;
  604    }
  605
  606    if style.background_color.is_none() {
  607        style.background_color = Some(cx.theme().status().hint_background);
  608    }
  609
  610    style
  611}
  612
  613pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  614    EditPredictionStyles {
  615        insertion: HighlightStyle {
  616            color: Some(cx.theme().status().predictive),
  617            ..HighlightStyle::default()
  618        },
  619        whitespace: HighlightStyle {
  620            background_color: Some(cx.theme().status().created_background),
  621            ..HighlightStyle::default()
  622        },
  623    }
  624}
  625
  626type CompletionId = usize;
  627
  628pub(crate) enum EditDisplayMode {
  629    TabAccept,
  630    DiffPopover,
  631    Inline,
  632}
  633
  634enum EditPrediction {
  635    Edit {
  636        edits: Vec<(Range<Anchor>, Arc<str>)>,
  637        edit_preview: Option<EditPreview>,
  638        display_mode: EditDisplayMode,
  639        snapshot: BufferSnapshot,
  640    },
  641    /// Move to a specific location in the active editor
  642    MoveWithin {
  643        target: Anchor,
  644        snapshot: BufferSnapshot,
  645    },
  646    /// Move to a specific location in a different editor (not the active one)
  647    MoveOutside {
  648        target: language::Anchor,
  649        snapshot: BufferSnapshot,
  650    },
  651}
  652
  653struct EditPredictionState {
  654    inlay_ids: Vec<InlayId>,
  655    completion: EditPrediction,
  656    completion_id: Option<SharedString>,
  657    invalidation_range: Option<Range<Anchor>>,
  658}
  659
  660enum EditPredictionSettings {
  661    Disabled,
  662    Enabled {
  663        show_in_menu: bool,
  664        preview_requires_modifier: bool,
  665    },
  666}
  667
  668enum EditPredictionHighlight {}
  669
  670#[derive(Debug, Clone)]
  671struct InlineDiagnostic {
  672    message: SharedString,
  673    group_id: usize,
  674    is_primary: bool,
  675    start: Point,
  676    severity: lsp::DiagnosticSeverity,
  677}
  678
  679pub enum MenuEditPredictionsPolicy {
  680    Never,
  681    ByProvider,
  682}
  683
  684pub enum EditPredictionPreview {
  685    /// Modifier is not pressed
  686    Inactive { released_too_fast: bool },
  687    /// Modifier pressed
  688    Active {
  689        since: Instant,
  690        previous_scroll_position: Option<ScrollAnchor>,
  691    },
  692}
  693
  694impl EditPredictionPreview {
  695    pub fn released_too_fast(&self) -> bool {
  696        match self {
  697            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  698            EditPredictionPreview::Active { .. } => false,
  699        }
  700    }
  701
  702    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  703        if let EditPredictionPreview::Active {
  704            previous_scroll_position,
  705            ..
  706        } = self
  707        {
  708            *previous_scroll_position = scroll_position;
  709        }
  710    }
  711}
  712
  713pub struct ContextMenuOptions {
  714    pub min_entries_visible: usize,
  715    pub max_entries_visible: usize,
  716    pub placement: Option<ContextMenuPlacement>,
  717}
  718
  719#[derive(Debug, Clone, PartialEq, Eq)]
  720pub enum ContextMenuPlacement {
  721    Above,
  722    Below,
  723}
  724
  725#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  726struct EditorActionId(usize);
  727
  728impl EditorActionId {
  729    pub fn post_inc(&mut self) -> Self {
  730        let answer = self.0;
  731
  732        *self = Self(answer + 1);
  733
  734        Self(answer)
  735    }
  736}
  737
  738// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  739// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  740
  741type BackgroundHighlight = (
  742    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  743    Arc<[Range<Anchor>]>,
  744);
  745type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  746
  747#[derive(Default)]
  748struct ScrollbarMarkerState {
  749    scrollbar_size: Size<Pixels>,
  750    dirty: bool,
  751    markers: Arc<[PaintQuad]>,
  752    pending_refresh: Option<Task<Result<()>>>,
  753}
  754
  755impl ScrollbarMarkerState {
  756    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  757        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  758    }
  759}
  760
  761#[derive(Clone, Copy, PartialEq, Eq)]
  762pub enum MinimapVisibility {
  763    Disabled,
  764    Enabled {
  765        /// The configuration currently present in the users settings.
  766        setting_configuration: bool,
  767        /// Whether to override the currently set visibility from the users setting.
  768        toggle_override: bool,
  769    },
  770}
  771
  772impl MinimapVisibility {
  773    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  774        if mode.is_full() {
  775            Self::Enabled {
  776                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  777                toggle_override: false,
  778            }
  779        } else {
  780            Self::Disabled
  781        }
  782    }
  783
  784    fn hidden(&self) -> Self {
  785        match *self {
  786            Self::Enabled {
  787                setting_configuration,
  788                ..
  789            } => Self::Enabled {
  790                setting_configuration,
  791                toggle_override: setting_configuration,
  792            },
  793            Self::Disabled => Self::Disabled,
  794        }
  795    }
  796
  797    fn disabled(&self) -> bool {
  798        matches!(*self, Self::Disabled)
  799    }
  800
  801    fn settings_visibility(&self) -> bool {
  802        match *self {
  803            Self::Enabled {
  804                setting_configuration,
  805                ..
  806            } => setting_configuration,
  807            _ => false,
  808        }
  809    }
  810
  811    fn visible(&self) -> bool {
  812        match *self {
  813            Self::Enabled {
  814                setting_configuration,
  815                toggle_override,
  816            } => setting_configuration ^ toggle_override,
  817            _ => false,
  818        }
  819    }
  820
  821    fn toggle_visibility(&self) -> Self {
  822        match *self {
  823            Self::Enabled {
  824                toggle_override,
  825                setting_configuration,
  826            } => Self::Enabled {
  827                setting_configuration,
  828                toggle_override: !toggle_override,
  829            },
  830            Self::Disabled => Self::Disabled,
  831        }
  832    }
  833}
  834
  835#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  836pub enum BufferSerialization {
  837    All,
  838    NonDirtyBuffers,
  839}
  840
  841impl BufferSerialization {
  842    fn new(restore_unsaved_buffers: bool) -> Self {
  843        if restore_unsaved_buffers {
  844            Self::All
  845        } else {
  846            Self::NonDirtyBuffers
  847        }
  848    }
  849}
  850
  851#[derive(Clone, Debug)]
  852struct RunnableTasks {
  853    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  854    offset: multi_buffer::Anchor,
  855    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  856    column: u32,
  857    // Values of all named captures, including those starting with '_'
  858    extra_variables: HashMap<String, String>,
  859    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  860    context_range: Range<BufferOffset>,
  861}
  862
  863impl RunnableTasks {
  864    fn resolve<'a>(
  865        &'a self,
  866        cx: &'a task::TaskContext,
  867    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  868        self.templates.iter().filter_map(|(kind, template)| {
  869            template
  870                .resolve_task(&kind.to_id_base(), cx)
  871                .map(|task| (kind.clone(), task))
  872        })
  873    }
  874}
  875
  876#[derive(Clone)]
  877pub struct ResolvedTasks {
  878    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  879    position: Anchor,
  880}
  881
  882/// Addons allow storing per-editor state in other crates (e.g. Vim)
  883pub trait Addon: 'static {
  884    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  885
  886    fn render_buffer_header_controls(
  887        &self,
  888        _: &ExcerptInfo,
  889        _: &Window,
  890        _: &App,
  891    ) -> Option<AnyElement> {
  892        None
  893    }
  894
  895    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  896        None
  897    }
  898
  899    fn to_any(&self) -> &dyn std::any::Any;
  900
  901    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  902        None
  903    }
  904}
  905
  906struct ChangeLocation {
  907    current: Option<Vec<Anchor>>,
  908    original: Vec<Anchor>,
  909}
  910impl ChangeLocation {
  911    fn locations(&self) -> &[Anchor] {
  912        self.current.as_ref().unwrap_or(&self.original)
  913    }
  914}
  915
  916/// A set of caret positions, registered when the editor was edited.
  917pub struct ChangeList {
  918    changes: Vec<ChangeLocation>,
  919    /// Currently "selected" change.
  920    position: Option<usize>,
  921}
  922
  923impl ChangeList {
  924    pub fn new() -> Self {
  925        Self {
  926            changes: Vec::new(),
  927            position: None,
  928        }
  929    }
  930
  931    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  932    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  933    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  934        if self.changes.is_empty() {
  935            return None;
  936        }
  937
  938        let prev = self.position.unwrap_or(self.changes.len());
  939        let next = if direction == Direction::Prev {
  940            prev.saturating_sub(count)
  941        } else {
  942            (prev + count).min(self.changes.len() - 1)
  943        };
  944        self.position = Some(next);
  945        self.changes.get(next).map(|change| change.locations())
  946    }
  947
  948    /// Adds a new change to the list, resetting the change list position.
  949    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  950        self.position.take();
  951        if let Some(last) = self.changes.last_mut()
  952            && group
  953        {
  954            last.current = Some(new_positions)
  955        } else {
  956            self.changes.push(ChangeLocation {
  957                original: new_positions,
  958                current: None,
  959            });
  960        }
  961    }
  962
  963    pub fn last(&self) -> Option<&[Anchor]> {
  964        self.changes.last().map(|change| change.locations())
  965    }
  966
  967    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  968        self.changes.last().map(|change| change.original.as_slice())
  969    }
  970
  971    pub fn invert_last_group(&mut self) {
  972        if let Some(last) = self.changes.last_mut()
  973            && let Some(current) = last.current.as_mut()
  974        {
  975            mem::swap(&mut last.original, current);
  976        }
  977    }
  978}
  979
  980#[derive(Clone)]
  981struct InlineBlamePopoverState {
  982    scroll_handle: ScrollHandle,
  983    commit_message: Option<ParsedCommitMessage>,
  984    markdown: Entity<Markdown>,
  985}
  986
  987struct InlineBlamePopover {
  988    position: gpui::Point<Pixels>,
  989    hide_task: Option<Task<()>>,
  990    popover_bounds: Option<Bounds<Pixels>>,
  991    popover_state: InlineBlamePopoverState,
  992    keyboard_grace: bool,
  993}
  994
  995enum SelectionDragState {
  996    /// State when no drag related activity is detected.
  997    None,
  998    /// State when the mouse is down on a selection that is about to be dragged.
  999    ReadyToDrag {
 1000        selection: Selection<Anchor>,
 1001        click_position: gpui::Point<Pixels>,
 1002        mouse_down_time: Instant,
 1003    },
 1004    /// State when the mouse is dragging the selection in the editor.
 1005    Dragging {
 1006        selection: Selection<Anchor>,
 1007        drop_cursor: Selection<Anchor>,
 1008        hide_drop_cursor: bool,
 1009    },
 1010}
 1011
 1012enum ColumnarSelectionState {
 1013    FromMouse {
 1014        selection_tail: Anchor,
 1015        display_point: Option<DisplayPoint>,
 1016    },
 1017    FromSelection {
 1018        selection_tail: Anchor,
 1019    },
 1020}
 1021
 1022/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1023/// a breakpoint on them.
 1024#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1025struct PhantomBreakpointIndicator {
 1026    display_row: DisplayRow,
 1027    /// There's a small debounce between hovering over the line and showing the indicator.
 1028    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1029    is_active: bool,
 1030    collides_with_existing_breakpoint: bool,
 1031}
 1032
 1033/// Represents a diff review button indicator that shows up when hovering over lines in the gutter
 1034/// in diff view mode.
 1035#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1036pub(crate) struct PhantomDiffReviewIndicator {
 1037    /// The starting anchor of the selection (or the only row if not dragging).
 1038    pub start: Anchor,
 1039    /// The ending anchor of the selection. Equal to start_anchor for single-line selection.
 1040    pub end: Anchor,
 1041    /// There's a small debounce between hovering over the line and showing the indicator.
 1042    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1043    pub is_active: bool,
 1044}
 1045
 1046#[derive(Clone, Debug)]
 1047pub(crate) struct DiffReviewDragState {
 1048    pub start_anchor: Anchor,
 1049    pub current_anchor: Anchor,
 1050}
 1051
 1052impl DiffReviewDragState {
 1053    pub fn row_range(&self, snapshot: &DisplaySnapshot) -> std::ops::RangeInclusive<DisplayRow> {
 1054        let start = self.start_anchor.to_display_point(snapshot).row();
 1055        let current = self.current_anchor.to_display_point(snapshot).row();
 1056
 1057        (start..=current).sorted()
 1058    }
 1059}
 1060
 1061/// Identifies a specific hunk in the diff buffer.
 1062/// Used as a key to group comments by their location.
 1063#[derive(Clone, Debug)]
 1064pub struct DiffHunkKey {
 1065    /// The file path (relative to worktree) this hunk belongs to.
 1066    pub file_path: Arc<util::rel_path::RelPath>,
 1067    /// An anchor at the start of the hunk. This tracks position as the buffer changes.
 1068    pub hunk_start_anchor: Anchor,
 1069}
 1070
 1071/// A review comment stored locally before being sent to the Agent panel.
 1072#[derive(Clone)]
 1073pub struct StoredReviewComment {
 1074    /// Unique identifier for this comment (for edit/delete operations).
 1075    pub id: usize,
 1076    /// The comment text entered by the user.
 1077    pub comment: String,
 1078    /// Anchors for the code range being reviewed.
 1079    pub range: Range<Anchor>,
 1080    /// Timestamp when the comment was created (for chronological ordering).
 1081    pub created_at: Instant,
 1082    /// Whether this comment is currently being edited inline.
 1083    pub is_editing: bool,
 1084}
 1085
 1086impl StoredReviewComment {
 1087    pub fn new(id: usize, comment: String, anchor_range: Range<Anchor>) -> Self {
 1088        Self {
 1089            id,
 1090            comment,
 1091            range: anchor_range,
 1092            created_at: Instant::now(),
 1093            is_editing: false,
 1094        }
 1095    }
 1096}
 1097
 1098/// Represents an active diff review overlay that appears when clicking the "Add Review" button.
 1099pub(crate) struct DiffReviewOverlay {
 1100    pub anchor_range: Range<Anchor>,
 1101    /// The block ID for the overlay.
 1102    pub block_id: CustomBlockId,
 1103    /// The editor entity for the review input.
 1104    pub prompt_editor: Entity<Editor>,
 1105    /// The hunk key this overlay belongs to.
 1106    pub hunk_key: DiffHunkKey,
 1107    /// Whether the comments section is expanded.
 1108    pub comments_expanded: bool,
 1109    /// Editors for comments currently being edited inline.
 1110    /// Key: comment ID, Value: Editor entity for inline editing.
 1111    pub inline_edit_editors: HashMap<usize, Entity<Editor>>,
 1112    /// Subscriptions for inline edit editors' action handlers.
 1113    /// Key: comment ID, Value: Subscription keeping the Newline action handler alive.
 1114    pub inline_edit_subscriptions: HashMap<usize, Subscription>,
 1115    /// The current user's avatar URI for display in comment rows.
 1116    pub user_avatar_uri: Option<SharedUri>,
 1117    /// Subscription to keep the action handler alive.
 1118    _subscription: Subscription,
 1119}
 1120
 1121/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1122///
 1123/// See the [module level documentation](self) for more information.
 1124pub struct Editor {
 1125    focus_handle: FocusHandle,
 1126    last_focused_descendant: Option<WeakFocusHandle>,
 1127    /// The text buffer being edited
 1128    buffer: Entity<MultiBuffer>,
 1129    /// Map of how text in the buffer should be displayed.
 1130    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1131    pub display_map: Entity<DisplayMap>,
 1132    placeholder_display_map: Option<Entity<DisplayMap>>,
 1133    pub selections: SelectionsCollection,
 1134    pub scroll_manager: ScrollManager,
 1135    /// When inline assist editors are linked, they all render cursors because
 1136    /// typing enters text into each of them, even the ones that aren't focused.
 1137    pub(crate) show_cursor_when_unfocused: bool,
 1138    columnar_selection_state: Option<ColumnarSelectionState>,
 1139    add_selections_state: Option<AddSelectionsState>,
 1140    select_next_state: Option<SelectNextState>,
 1141    select_prev_state: Option<SelectNextState>,
 1142    selection_history: SelectionHistory,
 1143    defer_selection_effects: bool,
 1144    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1145    autoclose_regions: Vec<AutocloseRegion>,
 1146    snippet_stack: InvalidationStack<SnippetState>,
 1147    select_syntax_node_history: SelectSyntaxNodeHistory,
 1148    ime_transaction: Option<TransactionId>,
 1149    pub diagnostics_max_severity: DiagnosticSeverity,
 1150    active_diagnostics: ActiveDiagnostic,
 1151    show_inline_diagnostics: bool,
 1152    inline_diagnostics_update: Task<()>,
 1153    inline_diagnostics_enabled: bool,
 1154    diagnostics_enabled: bool,
 1155    word_completions_enabled: bool,
 1156    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1157    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1158    hard_wrap: Option<usize>,
 1159    project: Option<Entity<Project>>,
 1160    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1161    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1162    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1163    blink_manager: Entity<BlinkManager>,
 1164    show_cursor_names: bool,
 1165    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1166    pub show_local_selections: bool,
 1167    mode: EditorMode,
 1168    show_breadcrumbs: bool,
 1169    show_gutter: bool,
 1170    show_scrollbars: ScrollbarAxes,
 1171    minimap_visibility: MinimapVisibility,
 1172    offset_content: bool,
 1173    disable_expand_excerpt_buttons: bool,
 1174    delegate_expand_excerpts: bool,
 1175    show_line_numbers: Option<bool>,
 1176    use_relative_line_numbers: Option<bool>,
 1177    show_git_diff_gutter: Option<bool>,
 1178    show_code_actions: Option<bool>,
 1179    show_runnables: Option<bool>,
 1180    show_breakpoints: Option<bool>,
 1181    show_diff_review_button: bool,
 1182    show_wrap_guides: Option<bool>,
 1183    show_indent_guides: Option<bool>,
 1184    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1185    highlight_order: usize,
 1186    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1187    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1188    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1189    scrollbar_marker_state: ScrollbarMarkerState,
 1190    active_indent_guides_state: ActiveIndentGuidesState,
 1191    nav_history: Option<ItemNavHistory>,
 1192    context_menu: RefCell<Option<CodeContextMenu>>,
 1193    context_menu_options: Option<ContextMenuOptions>,
 1194    mouse_context_menu: Option<MouseContextMenu>,
 1195    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1196    inline_blame_popover: Option<InlineBlamePopover>,
 1197    inline_blame_popover_show_task: Option<Task<()>>,
 1198    signature_help_state: SignatureHelpState,
 1199    auto_signature_help: Option<bool>,
 1200    find_all_references_task_sources: Vec<Anchor>,
 1201    next_completion_id: CompletionId,
 1202    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1203    code_actions_task: Option<Task<Result<()>>>,
 1204    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1205    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1206    debounced_selection_highlight_complete: bool,
 1207    document_highlights_task: Option<Task<()>>,
 1208    linked_editing_range_task: Option<Task<Option<()>>>,
 1209    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1210    pending_rename: Option<RenameState>,
 1211    searchable: bool,
 1212    cursor_shape: CursorShape,
 1213    /// Whether the cursor is offset one character to the left when something is
 1214    /// selected (needed for vim visual mode)
 1215    cursor_offset_on_selection: bool,
 1216    current_line_highlight: Option<CurrentLineHighlight>,
 1217    /// Whether to collapse search match ranges to just their start position.
 1218    /// When true, navigating to a match positions the cursor at the match
 1219    /// without selecting the matched text.
 1220    collapse_matches: bool,
 1221    autoindent_mode: Option<AutoindentMode>,
 1222    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1223    input_enabled: bool,
 1224    use_modal_editing: bool,
 1225    read_only: bool,
 1226    leader_id: Option<CollaboratorId>,
 1227    remote_id: Option<ViewId>,
 1228    pub hover_state: HoverState,
 1229    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1230    prev_pressure_stage: Option<PressureStage>,
 1231    gutter_hovered: bool,
 1232    hovered_link_state: Option<HoveredLinkState>,
 1233    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1234    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1235    active_edit_prediction: Option<EditPredictionState>,
 1236    /// Used to prevent flickering as the user types while the menu is open
 1237    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1238    edit_prediction_settings: EditPredictionSettings,
 1239    edit_predictions_hidden_for_vim_mode: bool,
 1240    show_edit_predictions_override: Option<bool>,
 1241    show_completions_on_input_override: Option<bool>,
 1242    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1243    edit_prediction_preview: EditPredictionPreview,
 1244    edit_prediction_indent_conflict: bool,
 1245    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1246    next_inlay_id: usize,
 1247    next_color_inlay_id: usize,
 1248    _subscriptions: Vec<Subscription>,
 1249    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1250    gutter_dimensions: GutterDimensions,
 1251    style: Option<EditorStyle>,
 1252    text_style_refinement: Option<TextStyleRefinement>,
 1253    next_editor_action_id: EditorActionId,
 1254    editor_actions: Rc<
 1255        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1256    >,
 1257    use_autoclose: bool,
 1258    use_auto_surround: bool,
 1259    auto_replace_emoji_shortcode: bool,
 1260    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1261    show_git_blame_gutter: bool,
 1262    show_git_blame_inline: bool,
 1263    show_git_blame_inline_delay_task: Option<Task<()>>,
 1264    git_blame_inline_enabled: bool,
 1265    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1266    buffer_serialization: Option<BufferSerialization>,
 1267    show_selection_menu: Option<bool>,
 1268    blame: Option<Entity<GitBlame>>,
 1269    blame_subscription: Option<Subscription>,
 1270    custom_context_menu: Option<
 1271        Box<
 1272            dyn 'static
 1273                + Fn(
 1274                    &mut Self,
 1275                    DisplayPoint,
 1276                    &mut Window,
 1277                    &mut Context<Self>,
 1278                ) -> Option<Entity<ui::ContextMenu>>,
 1279        >,
 1280    >,
 1281    last_bounds: Option<Bounds<Pixels>>,
 1282    last_position_map: Option<Rc<PositionMap>>,
 1283    expect_bounds_change: Option<Bounds<Pixels>>,
 1284    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1285    tasks_update_task: Option<Task<()>>,
 1286    breakpoint_store: Option<Entity<BreakpointStore>>,
 1287    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1288    pub(crate) gutter_diff_review_indicator: (Option<PhantomDiffReviewIndicator>, Option<Task<()>>),
 1289    pub(crate) diff_review_drag_state: Option<DiffReviewDragState>,
 1290    /// Active diff review overlays. Multiple overlays can be open simultaneously
 1291    /// when hunks have comments stored.
 1292    pub(crate) diff_review_overlays: Vec<DiffReviewOverlay>,
 1293    /// Stored review comments grouped by hunk.
 1294    /// Uses a Vec instead of HashMap because DiffHunkKey contains an Anchor
 1295    /// which doesn't implement Hash/Eq in a way suitable for HashMap keys.
 1296    stored_review_comments: Vec<(DiffHunkKey, Vec<StoredReviewComment>)>,
 1297    /// Counter for generating unique comment IDs.
 1298    next_review_comment_id: usize,
 1299    hovered_diff_hunk_row: Option<DisplayRow>,
 1300    pull_diagnostics_task: Task<()>,
 1301    in_project_search: bool,
 1302    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1303    breadcrumb_header: Option<String>,
 1304    focused_block: Option<FocusedBlock>,
 1305    next_scroll_position: NextScrollCursorCenterTopBottom,
 1306    addons: HashMap<TypeId, Box<dyn Addon>>,
 1307    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1308    load_diff_task: Option<Shared<Task<()>>>,
 1309    /// Whether we are temporarily displaying a diff other than git's
 1310    temporary_diff_override: bool,
 1311    selection_mark_mode: bool,
 1312    toggle_fold_multiple_buffers: Task<()>,
 1313    _scroll_cursor_center_top_bottom_task: Task<()>,
 1314    serialize_selections: Task<()>,
 1315    serialize_folds: Task<()>,
 1316    mouse_cursor_hidden: bool,
 1317    minimap: Option<Entity<Self>>,
 1318    hide_mouse_mode: HideMouseMode,
 1319    pub change_list: ChangeList,
 1320    inline_value_cache: InlineValueCache,
 1321    number_deleted_lines: bool,
 1322
 1323    selection_drag_state: SelectionDragState,
 1324    colors: Option<LspColorData>,
 1325    post_scroll_update: Task<()>,
 1326    refresh_colors_task: Task<()>,
 1327    inlay_hints: Option<LspInlayHintData>,
 1328    folding_newlines: Task<()>,
 1329    select_next_is_case_sensitive: Option<bool>,
 1330    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1331    scroll_companion: Option<WeakEntity<Editor>>,
 1332    on_local_selections_changed:
 1333        Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
 1334    suppress_selection_callback: bool,
 1335    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1336    accent_data: Option<AccentData>,
 1337    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1338}
 1339
 1340#[derive(Debug, PartialEq)]
 1341struct AccentData {
 1342    colors: AccentColors,
 1343    overrides: Vec<SharedString>,
 1344}
 1345
 1346fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1347    if debounce_ms > 0 {
 1348        Some(Duration::from_millis(debounce_ms))
 1349    } else {
 1350        None
 1351    }
 1352}
 1353
 1354#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1355enum NextScrollCursorCenterTopBottom {
 1356    #[default]
 1357    Center,
 1358    Top,
 1359    Bottom,
 1360}
 1361
 1362impl NextScrollCursorCenterTopBottom {
 1363    fn next(&self) -> Self {
 1364        match self {
 1365            Self::Center => Self::Top,
 1366            Self::Top => Self::Bottom,
 1367            Self::Bottom => Self::Center,
 1368        }
 1369    }
 1370}
 1371
 1372#[derive(Clone)]
 1373pub struct EditorSnapshot {
 1374    pub mode: EditorMode,
 1375    show_gutter: bool,
 1376    offset_content: bool,
 1377    show_line_numbers: Option<bool>,
 1378    number_deleted_lines: bool,
 1379    show_git_diff_gutter: Option<bool>,
 1380    show_code_actions: Option<bool>,
 1381    show_runnables: Option<bool>,
 1382    show_breakpoints: Option<bool>,
 1383    git_blame_gutter_max_author_length: Option<usize>,
 1384    pub display_snapshot: DisplaySnapshot,
 1385    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1386    is_focused: bool,
 1387    scroll_anchor: ScrollAnchor,
 1388    ongoing_scroll: OngoingScroll,
 1389    current_line_highlight: CurrentLineHighlight,
 1390    gutter_hovered: bool,
 1391}
 1392
 1393#[derive(Default, Debug, Clone, Copy)]
 1394pub struct GutterDimensions {
 1395    pub left_padding: Pixels,
 1396    pub right_padding: Pixels,
 1397    pub width: Pixels,
 1398    pub margin: Pixels,
 1399    pub git_blame_entries_width: Option<Pixels>,
 1400}
 1401
 1402impl GutterDimensions {
 1403    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1404        Self {
 1405            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1406            ..Default::default()
 1407        }
 1408    }
 1409
 1410    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1411        -cx.text_system().descent(font_id, font_size)
 1412    }
 1413    /// The full width of the space taken up by the gutter.
 1414    pub fn full_width(&self) -> Pixels {
 1415        self.margin + self.width
 1416    }
 1417
 1418    /// The width of the space reserved for the fold indicators,
 1419    /// use alongside 'justify_end' and `gutter_width` to
 1420    /// right align content with the line numbers
 1421    pub fn fold_area_width(&self) -> Pixels {
 1422        self.margin + self.right_padding
 1423    }
 1424}
 1425
 1426struct CharacterDimensions {
 1427    em_width: Pixels,
 1428    em_advance: Pixels,
 1429    line_height: Pixels,
 1430}
 1431
 1432#[derive(Debug)]
 1433pub struct RemoteSelection {
 1434    pub replica_id: ReplicaId,
 1435    pub selection: Selection<Anchor>,
 1436    pub cursor_shape: CursorShape,
 1437    pub collaborator_id: CollaboratorId,
 1438    pub line_mode: bool,
 1439    pub user_name: Option<SharedString>,
 1440    pub color: PlayerColor,
 1441}
 1442
 1443#[derive(Clone, Debug)]
 1444struct SelectionHistoryEntry {
 1445    selections: Arc<[Selection<Anchor>]>,
 1446    select_next_state: Option<SelectNextState>,
 1447    select_prev_state: Option<SelectNextState>,
 1448    add_selections_state: Option<AddSelectionsState>,
 1449}
 1450
 1451#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1452enum SelectionHistoryMode {
 1453    #[default]
 1454    Normal,
 1455    Undoing,
 1456    Redoing,
 1457    Skipping,
 1458}
 1459
 1460#[derive(Clone, PartialEq, Eq, Hash)]
 1461struct HoveredCursor {
 1462    replica_id: ReplicaId,
 1463    selection_id: usize,
 1464}
 1465
 1466#[derive(Debug)]
 1467/// SelectionEffects controls the side-effects of updating the selection.
 1468///
 1469/// The default behaviour does "what you mostly want":
 1470/// - it pushes to the nav history if the cursor moved by >10 lines
 1471/// - it re-triggers completion requests
 1472/// - it scrolls to fit
 1473///
 1474/// You might want to modify these behaviours. For example when doing a "jump"
 1475/// like go to definition, we always want to add to nav history; but when scrolling
 1476/// in vim mode we never do.
 1477///
 1478/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1479/// move.
 1480#[derive(Clone)]
 1481pub struct SelectionEffects {
 1482    nav_history: Option<bool>,
 1483    completions: bool,
 1484    scroll: Option<Autoscroll>,
 1485}
 1486
 1487impl Default for SelectionEffects {
 1488    fn default() -> Self {
 1489        Self {
 1490            nav_history: None,
 1491            completions: true,
 1492            scroll: Some(Autoscroll::fit()),
 1493        }
 1494    }
 1495}
 1496impl SelectionEffects {
 1497    pub fn scroll(scroll: Autoscroll) -> Self {
 1498        Self {
 1499            scroll: Some(scroll),
 1500            ..Default::default()
 1501        }
 1502    }
 1503
 1504    pub fn no_scroll() -> Self {
 1505        Self {
 1506            scroll: None,
 1507            ..Default::default()
 1508        }
 1509    }
 1510
 1511    pub fn completions(self, completions: bool) -> Self {
 1512        Self {
 1513            completions,
 1514            ..self
 1515        }
 1516    }
 1517
 1518    pub fn nav_history(self, nav_history: bool) -> Self {
 1519        Self {
 1520            nav_history: Some(nav_history),
 1521            ..self
 1522        }
 1523    }
 1524}
 1525
 1526struct DeferredSelectionEffectsState {
 1527    changed: bool,
 1528    effects: SelectionEffects,
 1529    old_cursor_position: Anchor,
 1530    history_entry: SelectionHistoryEntry,
 1531}
 1532
 1533#[derive(Default)]
 1534struct SelectionHistory {
 1535    #[allow(clippy::type_complexity)]
 1536    selections_by_transaction:
 1537        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1538    mode: SelectionHistoryMode,
 1539    undo_stack: VecDeque<SelectionHistoryEntry>,
 1540    redo_stack: VecDeque<SelectionHistoryEntry>,
 1541}
 1542
 1543impl SelectionHistory {
 1544    #[track_caller]
 1545    fn insert_transaction(
 1546        &mut self,
 1547        transaction_id: TransactionId,
 1548        selections: Arc<[Selection<Anchor>]>,
 1549    ) {
 1550        if selections.is_empty() {
 1551            log::error!(
 1552                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1553                std::panic::Location::caller()
 1554            );
 1555            return;
 1556        }
 1557        self.selections_by_transaction
 1558            .insert(transaction_id, (selections, None));
 1559    }
 1560
 1561    #[allow(clippy::type_complexity)]
 1562    fn transaction(
 1563        &self,
 1564        transaction_id: TransactionId,
 1565    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1566        self.selections_by_transaction.get(&transaction_id)
 1567    }
 1568
 1569    #[allow(clippy::type_complexity)]
 1570    fn transaction_mut(
 1571        &mut self,
 1572        transaction_id: TransactionId,
 1573    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1574        self.selections_by_transaction.get_mut(&transaction_id)
 1575    }
 1576
 1577    fn push(&mut self, entry: SelectionHistoryEntry) {
 1578        if !entry.selections.is_empty() {
 1579            match self.mode {
 1580                SelectionHistoryMode::Normal => {
 1581                    self.push_undo(entry);
 1582                    self.redo_stack.clear();
 1583                }
 1584                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1585                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1586                SelectionHistoryMode::Skipping => {}
 1587            }
 1588        }
 1589    }
 1590
 1591    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1592        if self
 1593            .undo_stack
 1594            .back()
 1595            .is_none_or(|e| e.selections != entry.selections)
 1596        {
 1597            self.undo_stack.push_back(entry);
 1598            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1599                self.undo_stack.pop_front();
 1600            }
 1601        }
 1602    }
 1603
 1604    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1605        if self
 1606            .redo_stack
 1607            .back()
 1608            .is_none_or(|e| e.selections != entry.selections)
 1609        {
 1610            self.redo_stack.push_back(entry);
 1611            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1612                self.redo_stack.pop_front();
 1613            }
 1614        }
 1615    }
 1616}
 1617
 1618#[derive(Clone, Copy)]
 1619pub struct RowHighlightOptions {
 1620    pub autoscroll: bool,
 1621    pub include_gutter: bool,
 1622}
 1623
 1624impl Default for RowHighlightOptions {
 1625    fn default() -> Self {
 1626        Self {
 1627            autoscroll: Default::default(),
 1628            include_gutter: true,
 1629        }
 1630    }
 1631}
 1632
 1633struct RowHighlight {
 1634    index: usize,
 1635    range: Range<Anchor>,
 1636    color: Hsla,
 1637    options: RowHighlightOptions,
 1638    type_id: TypeId,
 1639}
 1640
 1641#[derive(Clone, Debug)]
 1642struct AddSelectionsState {
 1643    groups: Vec<AddSelectionsGroup>,
 1644}
 1645
 1646#[derive(Clone, Debug)]
 1647struct AddSelectionsGroup {
 1648    above: bool,
 1649    stack: Vec<usize>,
 1650}
 1651
 1652#[derive(Clone)]
 1653struct SelectNextState {
 1654    query: AhoCorasick,
 1655    wordwise: bool,
 1656    done: bool,
 1657}
 1658
 1659impl std::fmt::Debug for SelectNextState {
 1660    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1661        f.debug_struct(std::any::type_name::<Self>())
 1662            .field("wordwise", &self.wordwise)
 1663            .field("done", &self.done)
 1664            .finish()
 1665    }
 1666}
 1667
 1668#[derive(Debug)]
 1669struct AutocloseRegion {
 1670    selection_id: usize,
 1671    range: Range<Anchor>,
 1672    pair: BracketPair,
 1673}
 1674
 1675#[derive(Debug)]
 1676struct SnippetState {
 1677    ranges: Vec<Vec<Range<Anchor>>>,
 1678    active_index: usize,
 1679    choices: Vec<Option<Vec<String>>>,
 1680}
 1681
 1682#[doc(hidden)]
 1683pub struct RenameState {
 1684    pub range: Range<Anchor>,
 1685    pub old_name: Arc<str>,
 1686    pub editor: Entity<Editor>,
 1687    block_id: CustomBlockId,
 1688}
 1689
 1690struct InvalidationStack<T>(Vec<T>);
 1691
 1692struct RegisteredEditPredictionDelegate {
 1693    provider: Arc<dyn EditPredictionDelegateHandle>,
 1694    _subscription: Subscription,
 1695}
 1696
 1697#[derive(Debug, PartialEq, Eq)]
 1698pub struct ActiveDiagnosticGroup {
 1699    pub active_range: Range<Anchor>,
 1700    pub active_message: String,
 1701    pub group_id: usize,
 1702    pub blocks: HashSet<CustomBlockId>,
 1703}
 1704
 1705#[derive(Debug, PartialEq, Eq)]
 1706
 1707pub(crate) enum ActiveDiagnostic {
 1708    None,
 1709    All,
 1710    Group(ActiveDiagnosticGroup),
 1711}
 1712
 1713#[derive(Serialize, Deserialize, Clone, Debug)]
 1714pub struct ClipboardSelection {
 1715    /// The number of bytes in this selection.
 1716    pub len: usize,
 1717    /// Whether this was a full-line selection.
 1718    pub is_entire_line: bool,
 1719    /// The indentation of the first line when this content was originally copied.
 1720    pub first_line_indent: u32,
 1721    #[serde(default)]
 1722    pub file_path: Option<PathBuf>,
 1723    #[serde(default)]
 1724    pub line_range: Option<RangeInclusive<u32>>,
 1725}
 1726
 1727impl ClipboardSelection {
 1728    pub fn for_buffer(
 1729        len: usize,
 1730        is_entire_line: bool,
 1731        range: Range<Point>,
 1732        buffer: &MultiBufferSnapshot,
 1733        project: Option<&Entity<Project>>,
 1734        cx: &App,
 1735    ) -> Self {
 1736        let first_line_indent = buffer
 1737            .indent_size_for_line(MultiBufferRow(range.start.row))
 1738            .len;
 1739
 1740        let file_path = util::maybe!({
 1741            let project = project?.read(cx);
 1742            let file = buffer.file_at(range.start)?;
 1743            let project_path = ProjectPath {
 1744                worktree_id: file.worktree_id(cx),
 1745                path: file.path().clone(),
 1746            };
 1747            project.absolute_path(&project_path, cx)
 1748        });
 1749
 1750        let line_range = file_path.as_ref().and_then(|_| {
 1751            let (_, start_point, start_excerpt_id) = buffer.point_to_buffer_point(range.start)?;
 1752            let (_, end_point, end_excerpt_id) = buffer.point_to_buffer_point(range.end)?;
 1753            if start_excerpt_id == end_excerpt_id {
 1754                Some(start_point.row..=end_point.row)
 1755            } else {
 1756                None
 1757            }
 1758        });
 1759
 1760        Self {
 1761            len,
 1762            is_entire_line,
 1763            first_line_indent,
 1764            file_path,
 1765            line_range,
 1766        }
 1767    }
 1768}
 1769
 1770// selections, scroll behavior, was newest selection reversed
 1771type SelectSyntaxNodeHistoryState = (
 1772    Box<[Selection<MultiBufferOffset>]>,
 1773    SelectSyntaxNodeScrollBehavior,
 1774    bool,
 1775);
 1776
 1777#[derive(Default)]
 1778struct SelectSyntaxNodeHistory {
 1779    stack: Vec<SelectSyntaxNodeHistoryState>,
 1780    // disable temporarily to allow changing selections without losing the stack
 1781    pub disable_clearing: bool,
 1782}
 1783
 1784impl SelectSyntaxNodeHistory {
 1785    pub fn try_clear(&mut self) {
 1786        if !self.disable_clearing {
 1787            self.stack.clear();
 1788        }
 1789    }
 1790
 1791    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1792        self.stack.push(selection);
 1793    }
 1794
 1795    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1796        self.stack.pop()
 1797    }
 1798}
 1799
 1800enum SelectSyntaxNodeScrollBehavior {
 1801    CursorTop,
 1802    FitSelection,
 1803    CursorBottom,
 1804}
 1805
 1806#[derive(Debug, Clone, Copy)]
 1807pub(crate) struct NavigationData {
 1808    cursor_anchor: Anchor,
 1809    cursor_position: Point,
 1810    scroll_anchor: ScrollAnchor,
 1811    scroll_top_row: u32,
 1812}
 1813
 1814#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1815pub enum GotoDefinitionKind {
 1816    Symbol,
 1817    Declaration,
 1818    Type,
 1819    Implementation,
 1820}
 1821
 1822pub enum FormatTarget {
 1823    Buffers(HashSet<Entity<Buffer>>),
 1824    Ranges(Vec<Range<MultiBufferPoint>>),
 1825}
 1826
 1827pub(crate) struct FocusedBlock {
 1828    id: BlockId,
 1829    focus_handle: WeakFocusHandle,
 1830}
 1831
 1832#[derive(Clone, Debug)]
 1833pub enum JumpData {
 1834    MultiBufferRow {
 1835        row: MultiBufferRow,
 1836        line_offset_from_top: u32,
 1837    },
 1838    MultiBufferPoint {
 1839        excerpt_id: ExcerptId,
 1840        position: Point,
 1841        anchor: text::Anchor,
 1842        line_offset_from_top: u32,
 1843    },
 1844}
 1845
 1846pub enum MultibufferSelectionMode {
 1847    First,
 1848    All,
 1849}
 1850
 1851#[derive(Clone, Copy, Debug, Default)]
 1852pub struct RewrapOptions {
 1853    pub override_language_settings: bool,
 1854    pub preserve_existing_whitespace: bool,
 1855}
 1856
 1857impl Editor {
 1858    pub fn single_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::SingleLine, buffer, None, window, cx)
 1862    }
 1863
 1864    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1865        let buffer = cx.new(|cx| Buffer::local("", cx));
 1866        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1867        Self::new(EditorMode::full(), buffer, None, window, cx)
 1868    }
 1869
 1870    pub fn auto_height(
 1871        min_lines: usize,
 1872        max_lines: usize,
 1873        window: &mut Window,
 1874        cx: &mut Context<Self>,
 1875    ) -> Self {
 1876        let buffer = cx.new(|cx| Buffer::local("", cx));
 1877        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1878        Self::new(
 1879            EditorMode::AutoHeight {
 1880                min_lines,
 1881                max_lines: Some(max_lines),
 1882            },
 1883            buffer,
 1884            None,
 1885            window,
 1886            cx,
 1887        )
 1888    }
 1889
 1890    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1891    /// The editor grows as tall as needed to fit its content.
 1892    pub fn auto_height_unbounded(
 1893        min_lines: usize,
 1894        window: &mut Window,
 1895        cx: &mut Context<Self>,
 1896    ) -> Self {
 1897        let buffer = cx.new(|cx| Buffer::local("", cx));
 1898        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1899        Self::new(
 1900            EditorMode::AutoHeight {
 1901                min_lines,
 1902                max_lines: None,
 1903            },
 1904            buffer,
 1905            None,
 1906            window,
 1907            cx,
 1908        )
 1909    }
 1910
 1911    pub fn for_buffer(
 1912        buffer: Entity<Buffer>,
 1913        project: Option<Entity<Project>>,
 1914        window: &mut Window,
 1915        cx: &mut Context<Self>,
 1916    ) -> Self {
 1917        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1918        Self::new(EditorMode::full(), buffer, project, window, cx)
 1919    }
 1920
 1921    pub fn for_multibuffer(
 1922        buffer: Entity<MultiBuffer>,
 1923        project: Option<Entity<Project>>,
 1924        window: &mut Window,
 1925        cx: &mut Context<Self>,
 1926    ) -> Self {
 1927        Self::new(EditorMode::full(), buffer, project, window, cx)
 1928    }
 1929
 1930    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1931        let mut clone = Self::new(
 1932            self.mode.clone(),
 1933            self.buffer.clone(),
 1934            self.project.clone(),
 1935            window,
 1936            cx,
 1937        );
 1938        self.display_map.update(cx, |display_map, cx| {
 1939            let snapshot = display_map.snapshot(cx);
 1940            clone.display_map.update(cx, |display_map, cx| {
 1941                display_map.set_state(&snapshot, cx);
 1942            });
 1943        });
 1944        clone.folds_did_change(cx);
 1945        clone.selections.clone_state(&self.selections);
 1946        clone.scroll_manager.clone_state(&self.scroll_manager);
 1947        clone.searchable = self.searchable;
 1948        clone.read_only = self.read_only;
 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 sticky_headers(
 1963        &self,
 1964        style: &EditorStyle,
 1965        cx: &App,
 1966    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1967        let multi_buffer = self.buffer().read(cx);
 1968        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1969        let multi_buffer_visible_start = self
 1970            .scroll_manager
 1971            .anchor()
 1972            .anchor
 1973            .to_point(&multi_buffer_snapshot);
 1974        let max_row = multi_buffer_snapshot.max_point().row;
 1975
 1976        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1977        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1978
 1979        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1980            let outline_items = buffer
 1981                .outline_items_containing(
 1982                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1983                    true,
 1984                    Some(style.syntax.as_ref()),
 1985                )
 1986                .into_iter()
 1987                .map(|outline_item| OutlineItem {
 1988                    depth: outline_item.depth,
 1989                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1990                    source_range_for_text: Anchor::range_in_buffer(
 1991                        *excerpt_id,
 1992                        outline_item.source_range_for_text,
 1993                    ),
 1994                    text: outline_item.text,
 1995                    highlight_ranges: outline_item.highlight_ranges,
 1996                    name_ranges: outline_item.name_ranges,
 1997                    body_range: outline_item
 1998                        .body_range
 1999                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 2000                    annotation_range: outline_item
 2001                        .annotation_range
 2002                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 2003                });
 2004            return Some(outline_items.collect());
 2005        }
 2006
 2007        None
 2008    }
 2009
 2010    fn new_internal(
 2011        mode: EditorMode,
 2012        multi_buffer: Entity<MultiBuffer>,
 2013        project: Option<Entity<Project>>,
 2014        display_map: Option<Entity<DisplayMap>>,
 2015        window: &mut Window,
 2016        cx: &mut Context<Self>,
 2017    ) -> Self {
 2018        debug_assert!(
 2019            display_map.is_none() || mode.is_minimap(),
 2020            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 2021        );
 2022
 2023        let full_mode = mode.is_full();
 2024        let is_minimap = mode.is_minimap();
 2025        let diagnostics_max_severity = if full_mode {
 2026            EditorSettings::get_global(cx)
 2027                .diagnostics_max_severity
 2028                .unwrap_or(DiagnosticSeverity::Hint)
 2029        } else {
 2030            DiagnosticSeverity::Off
 2031        };
 2032        let style = window.text_style();
 2033        let font_size = style.font_size.to_pixels(window.rem_size());
 2034        let editor = cx.entity().downgrade();
 2035        let fold_placeholder = FoldPlaceholder {
 2036            constrain_width: false,
 2037            render: Arc::new(move |fold_id, fold_range, cx| {
 2038                let editor = editor.clone();
 2039                div()
 2040                    .id(fold_id)
 2041                    .bg(cx.theme().colors().ghost_element_background)
 2042                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 2043                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 2044                    .rounded_xs()
 2045                    .size_full()
 2046                    .cursor_pointer()
 2047                    .child("")
 2048                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 2049                    .on_click(move |_, _window, cx| {
 2050                        editor
 2051                            .update(cx, |editor, cx| {
 2052                                editor.unfold_ranges(
 2053                                    &[fold_range.start..fold_range.end],
 2054                                    true,
 2055                                    false,
 2056                                    cx,
 2057                                );
 2058                                cx.stop_propagation();
 2059                            })
 2060                            .ok();
 2061                    })
 2062                    .into_any()
 2063            }),
 2064            merge_adjacent: true,
 2065            ..FoldPlaceholder::default()
 2066        };
 2067        let display_map = display_map.unwrap_or_else(|| {
 2068            cx.new(|cx| {
 2069                DisplayMap::new(
 2070                    multi_buffer.clone(),
 2071                    style.font(),
 2072                    font_size,
 2073                    None,
 2074                    FILE_HEADER_HEIGHT,
 2075                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2076                    fold_placeholder,
 2077                    diagnostics_max_severity,
 2078                    cx,
 2079                )
 2080            })
 2081        });
 2082
 2083        let selections = SelectionsCollection::new();
 2084
 2085        let blink_manager = cx.new(|cx| {
 2086            let mut blink_manager = BlinkManager::new(
 2087                CURSOR_BLINK_INTERVAL,
 2088                |cx| EditorSettings::get_global(cx).cursor_blink,
 2089                cx,
 2090            );
 2091            if is_minimap {
 2092                blink_manager.disable(cx);
 2093            }
 2094            blink_manager
 2095        });
 2096
 2097        let soft_wrap_mode_override =
 2098            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 2099
 2100        let mut project_subscriptions = Vec::new();
 2101        if full_mode && let Some(project) = project.as_ref() {
 2102            project_subscriptions.push(cx.subscribe_in(
 2103                project,
 2104                window,
 2105                |editor, _, event, window, cx| match event {
 2106                    project::Event::RefreshCodeLens => {
 2107                        // we always query lens with actions, without storing them, always refreshing them
 2108                    }
 2109                    project::Event::RefreshInlayHints {
 2110                        server_id,
 2111                        request_id,
 2112                    } => {
 2113                        editor.refresh_inlay_hints(
 2114                            InlayHintRefreshReason::RefreshRequested {
 2115                                server_id: *server_id,
 2116                                request_id: *request_id,
 2117                            },
 2118                            cx,
 2119                        );
 2120                    }
 2121                    project::Event::LanguageServerRemoved(..) => {
 2122                        if editor.tasks_update_task.is_none() {
 2123                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2124                        }
 2125                        editor.registered_buffers.clear();
 2126                        editor.register_visible_buffers(cx);
 2127                    }
 2128                    project::Event::LanguageServerAdded(..) => {
 2129                        if editor.tasks_update_task.is_none() {
 2130                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2131                        }
 2132                    }
 2133                    project::Event::SnippetEdit(id, snippet_edits) => {
 2134                        // todo(lw): Non singletons
 2135                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2136                            let snapshot = buffer.read(cx).snapshot();
 2137                            let focus_handle = editor.focus_handle(cx);
 2138                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2139                                for (range, snippet) in snippet_edits {
 2140                                    let buffer_range =
 2141                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2142                                    editor
 2143                                        .insert_snippet(
 2144                                            &[MultiBufferOffset(buffer_range.start)
 2145                                                ..MultiBufferOffset(buffer_range.end)],
 2146                                            snippet.clone(),
 2147                                            window,
 2148                                            cx,
 2149                                        )
 2150                                        .ok();
 2151                                }
 2152                            }
 2153                        }
 2154                    }
 2155                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2156                        let buffer_id = *buffer_id;
 2157                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2158                            editor.register_buffer(buffer_id, cx);
 2159                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2160                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2161                            refresh_linked_ranges(editor, window, cx);
 2162                            editor.refresh_code_actions(window, cx);
 2163                            editor.refresh_document_highlights(cx);
 2164                        }
 2165                    }
 2166
 2167                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2168                        let Some(workspace) = editor.workspace() else {
 2169                            return;
 2170                        };
 2171                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2172                        else {
 2173                            return;
 2174                        };
 2175
 2176                        if active_editor.entity_id() == cx.entity_id() {
 2177                            let entity_id = cx.entity_id();
 2178                            workspace.update(cx, |this, cx| {
 2179                                this.panes_mut()
 2180                                    .iter_mut()
 2181                                    .filter(|pane| pane.entity_id() != entity_id)
 2182                                    .for_each(|p| {
 2183                                        p.update(cx, |pane, _| {
 2184                                            pane.nav_history_mut().rename_item(
 2185                                                entity_id,
 2186                                                project_path.clone(),
 2187                                                abs_path.clone().into(),
 2188                                            );
 2189                                        })
 2190                                    });
 2191                            });
 2192
 2193                            Self::open_transaction_for_hidden_buffers(
 2194                                workspace,
 2195                                transaction.clone(),
 2196                                "Rename".to_string(),
 2197                                window,
 2198                                cx,
 2199                            );
 2200                        }
 2201                    }
 2202
 2203                    project::Event::WorkspaceEditApplied(transaction) => {
 2204                        let Some(workspace) = editor.workspace() else {
 2205                            return;
 2206                        };
 2207                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2208                        else {
 2209                            return;
 2210                        };
 2211
 2212                        if active_editor.entity_id() == cx.entity_id() {
 2213                            Self::open_transaction_for_hidden_buffers(
 2214                                workspace,
 2215                                transaction.clone(),
 2216                                "LSP Edit".to_string(),
 2217                                window,
 2218                                cx,
 2219                            );
 2220                        }
 2221                    }
 2222
 2223                    _ => {}
 2224                },
 2225            ));
 2226            if let Some(task_inventory) = project
 2227                .read(cx)
 2228                .task_store()
 2229                .read(cx)
 2230                .task_inventory()
 2231                .cloned()
 2232            {
 2233                project_subscriptions.push(cx.observe_in(
 2234                    &task_inventory,
 2235                    window,
 2236                    |editor, _, window, cx| {
 2237                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2238                    },
 2239                ));
 2240            };
 2241
 2242            project_subscriptions.push(cx.subscribe_in(
 2243                &project.read(cx).breakpoint_store(),
 2244                window,
 2245                |editor, _, event, window, cx| match event {
 2246                    BreakpointStoreEvent::ClearDebugLines => {
 2247                        editor.clear_row_highlights::<ActiveDebugLine>();
 2248                        editor.refresh_inline_values(cx);
 2249                    }
 2250                    BreakpointStoreEvent::SetDebugLine => {
 2251                        if editor.go_to_active_debug_line(window, cx) {
 2252                            cx.stop_propagation();
 2253                        }
 2254
 2255                        editor.refresh_inline_values(cx);
 2256                    }
 2257                    _ => {}
 2258                },
 2259            ));
 2260            let git_store = project.read(cx).git_store().clone();
 2261            let project = project.clone();
 2262            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2263                if let GitStoreEvent::RepositoryAdded = event {
 2264                    this.load_diff_task = Some(
 2265                        update_uncommitted_diff_for_buffer(
 2266                            cx.entity(),
 2267                            &project,
 2268                            this.buffer.read(cx).all_buffers(),
 2269                            this.buffer.clone(),
 2270                            cx,
 2271                        )
 2272                        .shared(),
 2273                    );
 2274                }
 2275            }));
 2276        }
 2277
 2278        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2279
 2280        let inlay_hint_settings =
 2281            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2282        let focus_handle = cx.focus_handle();
 2283        if !is_minimap {
 2284            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2285                .detach();
 2286            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2287                .detach();
 2288            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2289                .detach();
 2290            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2291                .detach();
 2292            cx.observe_pending_input(window, Self::observe_pending_input)
 2293                .detach();
 2294        }
 2295
 2296        let show_indent_guides =
 2297            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2298                Some(false)
 2299            } else {
 2300                None
 2301            };
 2302
 2303        let breakpoint_store = match (&mode, project.as_ref()) {
 2304            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2305            _ => None,
 2306        };
 2307
 2308        let mut code_action_providers = Vec::new();
 2309        let mut load_uncommitted_diff = None;
 2310        if let Some(project) = project.clone() {
 2311            load_uncommitted_diff = Some(
 2312                update_uncommitted_diff_for_buffer(
 2313                    cx.entity(),
 2314                    &project,
 2315                    multi_buffer.read(cx).all_buffers(),
 2316                    multi_buffer.clone(),
 2317                    cx,
 2318                )
 2319                .shared(),
 2320            );
 2321            code_action_providers.push(Rc::new(project) as Rc<_>);
 2322        }
 2323
 2324        let mut editor = Self {
 2325            focus_handle,
 2326            show_cursor_when_unfocused: false,
 2327            last_focused_descendant: None,
 2328            buffer: multi_buffer.clone(),
 2329            display_map: display_map.clone(),
 2330            placeholder_display_map: None,
 2331            selections,
 2332            scroll_manager: ScrollManager::new(cx),
 2333            columnar_selection_state: None,
 2334            add_selections_state: None,
 2335            select_next_state: None,
 2336            select_prev_state: None,
 2337            selection_history: SelectionHistory::default(),
 2338            defer_selection_effects: false,
 2339            deferred_selection_effects_state: None,
 2340            autoclose_regions: Vec::new(),
 2341            snippet_stack: InvalidationStack::default(),
 2342            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2343            ime_transaction: None,
 2344            active_diagnostics: ActiveDiagnostic::None,
 2345            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2346            inline_diagnostics_update: Task::ready(()),
 2347            inline_diagnostics: Vec::new(),
 2348            soft_wrap_mode_override,
 2349            diagnostics_max_severity,
 2350            hard_wrap: None,
 2351            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2352            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2353            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2354            project,
 2355            blink_manager: blink_manager.clone(),
 2356            show_local_selections: true,
 2357            show_scrollbars: ScrollbarAxes {
 2358                horizontal: full_mode,
 2359                vertical: full_mode,
 2360            },
 2361            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2362            offset_content: !matches!(mode, EditorMode::SingleLine),
 2363            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2364            show_gutter: full_mode,
 2365            show_line_numbers: (!full_mode).then_some(false),
 2366            use_relative_line_numbers: None,
 2367            disable_expand_excerpt_buttons: !full_mode,
 2368            delegate_expand_excerpts: false,
 2369            show_git_diff_gutter: None,
 2370            show_code_actions: None,
 2371            show_runnables: None,
 2372            show_breakpoints: None,
 2373            show_diff_review_button: false,
 2374            show_wrap_guides: None,
 2375            show_indent_guides,
 2376            buffers_with_disabled_indent_guides: HashSet::default(),
 2377            highlight_order: 0,
 2378            highlighted_rows: HashMap::default(),
 2379            background_highlights: HashMap::default(),
 2380            gutter_highlights: HashMap::default(),
 2381            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2382            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2383            nav_history: None,
 2384            context_menu: RefCell::new(None),
 2385            context_menu_options: None,
 2386            mouse_context_menu: None,
 2387            completion_tasks: Vec::new(),
 2388            inline_blame_popover: None,
 2389            inline_blame_popover_show_task: None,
 2390            signature_help_state: SignatureHelpState::default(),
 2391            auto_signature_help: None,
 2392            find_all_references_task_sources: Vec::new(),
 2393            next_completion_id: 0,
 2394            next_inlay_id: 0,
 2395            code_action_providers,
 2396            available_code_actions: None,
 2397            code_actions_task: None,
 2398            quick_selection_highlight_task: None,
 2399            debounced_selection_highlight_task: None,
 2400            debounced_selection_highlight_complete: false,
 2401            document_highlights_task: None,
 2402            linked_editing_range_task: None,
 2403            pending_rename: None,
 2404            searchable: !is_minimap,
 2405            cursor_shape: EditorSettings::get_global(cx)
 2406                .cursor_shape
 2407                .unwrap_or_default(),
 2408            cursor_offset_on_selection: false,
 2409            current_line_highlight: None,
 2410            autoindent_mode: Some(AutoindentMode::EachLine),
 2411            collapse_matches: false,
 2412            workspace: None,
 2413            input_enabled: !is_minimap,
 2414            use_modal_editing: full_mode,
 2415            read_only: is_minimap,
 2416            use_autoclose: true,
 2417            use_auto_surround: true,
 2418            auto_replace_emoji_shortcode: false,
 2419            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2420            leader_id: None,
 2421            remote_id: None,
 2422            hover_state: HoverState::default(),
 2423            pending_mouse_down: None,
 2424            prev_pressure_stage: None,
 2425            hovered_link_state: None,
 2426            edit_prediction_provider: None,
 2427            active_edit_prediction: None,
 2428            stale_edit_prediction_in_menu: None,
 2429            edit_prediction_preview: EditPredictionPreview::Inactive {
 2430                released_too_fast: false,
 2431            },
 2432            inline_diagnostics_enabled: full_mode,
 2433            diagnostics_enabled: full_mode,
 2434            word_completions_enabled: full_mode,
 2435            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2436            gutter_hovered: false,
 2437            pixel_position_of_newest_cursor: None,
 2438            last_bounds: None,
 2439            last_position_map: None,
 2440            expect_bounds_change: None,
 2441            gutter_dimensions: GutterDimensions::default(),
 2442            style: None,
 2443            show_cursor_names: false,
 2444            hovered_cursors: HashMap::default(),
 2445            next_editor_action_id: EditorActionId::default(),
 2446            editor_actions: Rc::default(),
 2447            edit_predictions_hidden_for_vim_mode: false,
 2448            show_edit_predictions_override: None,
 2449            show_completions_on_input_override: None,
 2450            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2451            edit_prediction_settings: EditPredictionSettings::Disabled,
 2452            edit_prediction_indent_conflict: false,
 2453            edit_prediction_requires_modifier_in_indent_conflict: true,
 2454            custom_context_menu: None,
 2455            show_git_blame_gutter: false,
 2456            show_git_blame_inline: false,
 2457            show_selection_menu: None,
 2458            show_git_blame_inline_delay_task: None,
 2459            git_blame_inline_enabled: full_mode
 2460                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2461            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2462            buffer_serialization: is_minimap.not().then(|| {
 2463                BufferSerialization::new(
 2464                    ProjectSettings::get_global(cx)
 2465                        .session
 2466                        .restore_unsaved_buffers,
 2467                )
 2468            }),
 2469            blame: None,
 2470            blame_subscription: None,
 2471            tasks: BTreeMap::default(),
 2472
 2473            breakpoint_store,
 2474            gutter_breakpoint_indicator: (None, None),
 2475            gutter_diff_review_indicator: (None, None),
 2476            diff_review_drag_state: None,
 2477            diff_review_overlays: Vec::new(),
 2478            stored_review_comments: Vec::new(),
 2479            next_review_comment_id: 0,
 2480            hovered_diff_hunk_row: None,
 2481            _subscriptions: (!is_minimap)
 2482                .then(|| {
 2483                    vec![
 2484                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2485                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2486                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2487                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2488                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2489                        cx.observe_global_in::<GlobalTheme>(window, Self::theme_changed),
 2490                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2491                        cx.observe_window_activation(window, |editor, window, cx| {
 2492                            let active = window.is_window_active();
 2493                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2494                                if active {
 2495                                    blink_manager.enable(cx);
 2496                                } else {
 2497                                    blink_manager.disable(cx);
 2498                                }
 2499                            });
 2500                            if active {
 2501                                editor.show_mouse_cursor(cx);
 2502                            }
 2503                        }),
 2504                    ]
 2505                })
 2506                .unwrap_or_default(),
 2507            tasks_update_task: None,
 2508            pull_diagnostics_task: Task::ready(()),
 2509            colors: None,
 2510            refresh_colors_task: Task::ready(()),
 2511            inlay_hints: None,
 2512            next_color_inlay_id: 0,
 2513            post_scroll_update: Task::ready(()),
 2514            linked_edit_ranges: Default::default(),
 2515            in_project_search: false,
 2516            previous_search_ranges: None,
 2517            breadcrumb_header: None,
 2518            focused_block: None,
 2519            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2520            addons: HashMap::default(),
 2521            registered_buffers: HashMap::default(),
 2522            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2523            selection_mark_mode: false,
 2524            toggle_fold_multiple_buffers: Task::ready(()),
 2525            serialize_selections: Task::ready(()),
 2526            serialize_folds: Task::ready(()),
 2527            text_style_refinement: None,
 2528            load_diff_task: load_uncommitted_diff,
 2529            temporary_diff_override: false,
 2530            mouse_cursor_hidden: false,
 2531            minimap: None,
 2532            hide_mouse_mode: EditorSettings::get_global(cx)
 2533                .hide_mouse
 2534                .unwrap_or_default(),
 2535            change_list: ChangeList::new(),
 2536            mode,
 2537            selection_drag_state: SelectionDragState::None,
 2538            folding_newlines: Task::ready(()),
 2539            lookup_key: None,
 2540            select_next_is_case_sensitive: None,
 2541            scroll_companion: None,
 2542            on_local_selections_changed: None,
 2543            suppress_selection_callback: false,
 2544            applicable_language_settings: HashMap::default(),
 2545            accent_data: None,
 2546            fetched_tree_sitter_chunks: HashMap::default(),
 2547            number_deleted_lines: false,
 2548        };
 2549
 2550        if is_minimap {
 2551            return editor;
 2552        }
 2553
 2554        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2555        editor.accent_data = editor.fetch_accent_data(cx);
 2556
 2557        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2558            editor
 2559                ._subscriptions
 2560                .push(cx.observe(breakpoints, |_, _, cx| {
 2561                    cx.notify();
 2562                }));
 2563        }
 2564        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2565        editor._subscriptions.extend(project_subscriptions);
 2566
 2567        editor._subscriptions.push(cx.subscribe_in(
 2568            &cx.entity(),
 2569            window,
 2570            |editor, _, e: &EditorEvent, window, cx| match e {
 2571                EditorEvent::ScrollPositionChanged { local, .. } => {
 2572                    if *local {
 2573                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2574                        editor.inline_blame_popover.take();
 2575                        let new_anchor = editor.scroll_manager.anchor();
 2576                        let snapshot = editor.snapshot(window, cx);
 2577                        editor.update_restoration_data(cx, move |data| {
 2578                            data.scroll_position = (
 2579                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2580                                new_anchor.offset,
 2581                            );
 2582                        });
 2583
 2584                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2585                            cx.background_executor()
 2586                                .timer(Duration::from_millis(50))
 2587                                .await;
 2588                            editor
 2589                                .update_in(cx, |editor, window, cx| {
 2590                                    editor.register_visible_buffers(cx);
 2591                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2592                                    editor.refresh_inlay_hints(
 2593                                        InlayHintRefreshReason::NewLinesShown,
 2594                                        cx,
 2595                                    );
 2596                                    editor.colorize_brackets(false, cx);
 2597                                })
 2598                                .ok();
 2599                        });
 2600                    }
 2601                }
 2602                EditorEvent::Edited { .. } => {
 2603                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2604                        .map(|vim_mode| vim_mode.0)
 2605                        .unwrap_or(false);
 2606                    if !vim_mode {
 2607                        let display_map = editor.display_snapshot(cx);
 2608                        let selections = editor.selections.all_adjusted_display(&display_map);
 2609                        let pop_state = editor
 2610                            .change_list
 2611                            .last()
 2612                            .map(|previous| {
 2613                                previous.len() == selections.len()
 2614                                    && previous.iter().enumerate().all(|(ix, p)| {
 2615                                        p.to_display_point(&display_map).row()
 2616                                            == selections[ix].head().row()
 2617                                    })
 2618                            })
 2619                            .unwrap_or(false);
 2620                        let new_positions = selections
 2621                            .into_iter()
 2622                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2623                            .collect();
 2624                        editor
 2625                            .change_list
 2626                            .push_to_change_list(pop_state, new_positions);
 2627                    }
 2628                }
 2629                _ => (),
 2630            },
 2631        ));
 2632
 2633        if let Some(dap_store) = editor
 2634            .project
 2635            .as_ref()
 2636            .map(|project| project.read(cx).dap_store())
 2637        {
 2638            let weak_editor = cx.weak_entity();
 2639
 2640            editor
 2641                ._subscriptions
 2642                .push(
 2643                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2644                        let session_entity = cx.entity();
 2645                        weak_editor
 2646                            .update(cx, |editor, cx| {
 2647                                editor._subscriptions.push(
 2648                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2649                                );
 2650                            })
 2651                            .ok();
 2652                    }),
 2653                );
 2654
 2655            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2656                editor
 2657                    ._subscriptions
 2658                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2659            }
 2660        }
 2661
 2662        // skip adding the initial selection to selection history
 2663        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2664        editor.end_selection(window, cx);
 2665        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2666
 2667        editor.scroll_manager.show_scrollbars(window, cx);
 2668        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2669
 2670        if full_mode {
 2671            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2672            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2673
 2674            if editor.git_blame_inline_enabled {
 2675                editor.start_git_blame_inline(false, window, cx);
 2676            }
 2677
 2678            editor.go_to_active_debug_line(window, cx);
 2679
 2680            editor.minimap =
 2681                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2682            editor.colors = Some(LspColorData::new(cx));
 2683            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2684
 2685            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2686                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2687            }
 2688            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2689        }
 2690
 2691        editor
 2692    }
 2693
 2694    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2695        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2696    }
 2697
 2698    pub fn deploy_mouse_context_menu(
 2699        &mut self,
 2700        position: gpui::Point<Pixels>,
 2701        context_menu: Entity<ContextMenu>,
 2702        window: &mut Window,
 2703        cx: &mut Context<Self>,
 2704    ) {
 2705        self.mouse_context_menu = Some(MouseContextMenu::new(
 2706            self,
 2707            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2708            context_menu,
 2709            window,
 2710            cx,
 2711        ));
 2712    }
 2713
 2714    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2715        self.mouse_context_menu
 2716            .as_ref()
 2717            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2718    }
 2719
 2720    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2721        if self
 2722            .selections
 2723            .pending_anchor()
 2724            .is_some_and(|pending_selection| {
 2725                let snapshot = self.buffer().read(cx).snapshot(cx);
 2726                pending_selection.range().includes(range, &snapshot)
 2727            })
 2728        {
 2729            return true;
 2730        }
 2731
 2732        self.selections
 2733            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2734            .into_iter()
 2735            .any(|selection| {
 2736                // This is needed to cover a corner case, if we just check for an existing
 2737                // selection in the fold range, having a cursor at the start of the fold
 2738                // marks it as selected. Non-empty selections don't cause this.
 2739                let length = selection.end - selection.start;
 2740                length > 0
 2741            })
 2742    }
 2743
 2744    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2745        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2746    }
 2747
 2748    fn key_context_internal(
 2749        &self,
 2750        has_active_edit_prediction: bool,
 2751        window: &mut Window,
 2752        cx: &mut App,
 2753    ) -> KeyContext {
 2754        let mut key_context = KeyContext::new_with_defaults();
 2755        key_context.add("Editor");
 2756        let mode = match self.mode {
 2757            EditorMode::SingleLine => "single_line",
 2758            EditorMode::AutoHeight { .. } => "auto_height",
 2759            EditorMode::Minimap { .. } => "minimap",
 2760            EditorMode::Full { .. } => "full",
 2761        };
 2762
 2763        if EditorSettings::jupyter_enabled(cx) {
 2764            key_context.add("jupyter");
 2765        }
 2766
 2767        key_context.set("mode", mode);
 2768        if self.pending_rename.is_some() {
 2769            key_context.add("renaming");
 2770        }
 2771
 2772        if let Some(snippet_stack) = self.snippet_stack.last() {
 2773            key_context.add("in_snippet");
 2774
 2775            if snippet_stack.active_index > 0 {
 2776                key_context.add("has_previous_tabstop");
 2777            }
 2778
 2779            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2780                key_context.add("has_next_tabstop");
 2781            }
 2782        }
 2783
 2784        match self.context_menu.borrow().as_ref() {
 2785            Some(CodeContextMenu::Completions(menu)) => {
 2786                if menu.visible() {
 2787                    key_context.add("menu");
 2788                    key_context.add("showing_completions");
 2789                }
 2790            }
 2791            Some(CodeContextMenu::CodeActions(menu)) => {
 2792                if menu.visible() {
 2793                    key_context.add("menu");
 2794                    key_context.add("showing_code_actions")
 2795                }
 2796            }
 2797            None => {}
 2798        }
 2799
 2800        if self.signature_help_state.has_multiple_signatures() {
 2801            key_context.add("showing_signature_help");
 2802        }
 2803
 2804        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2805        if !self.focus_handle(cx).contains_focused(window, cx)
 2806            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2807        {
 2808            for addon in self.addons.values() {
 2809                addon.extend_key_context(&mut key_context, cx)
 2810            }
 2811        }
 2812
 2813        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2814            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2815                Some(
 2816                    file.full_path(cx)
 2817                        .extension()?
 2818                        .to_string_lossy()
 2819                        .to_lowercase(),
 2820                )
 2821            }) {
 2822                key_context.set("extension", extension);
 2823            }
 2824        } else {
 2825            key_context.add("multibuffer");
 2826        }
 2827
 2828        if has_active_edit_prediction {
 2829            if self.edit_prediction_in_conflict() {
 2830                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2831            } else {
 2832                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2833                key_context.add("copilot_suggestion");
 2834            }
 2835        }
 2836
 2837        if self.selection_mark_mode {
 2838            key_context.add("selection_mode");
 2839        }
 2840
 2841        let disjoint = self.selections.disjoint_anchors();
 2842        let snapshot = self.snapshot(window, cx);
 2843        let snapshot = snapshot.buffer_snapshot();
 2844        if self.mode == EditorMode::SingleLine
 2845            && let [selection] = disjoint
 2846            && selection.start == selection.end
 2847            && selection.end.to_offset(snapshot) == snapshot.len()
 2848        {
 2849            key_context.add("end_of_input");
 2850        }
 2851
 2852        if self.has_any_expanded_diff_hunks(cx) {
 2853            key_context.add("diffs_expanded");
 2854        }
 2855
 2856        key_context
 2857    }
 2858
 2859    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2860        self.last_bounds.as_ref()
 2861    }
 2862
 2863    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2864        if self.mouse_cursor_hidden {
 2865            self.mouse_cursor_hidden = false;
 2866            cx.notify();
 2867        }
 2868    }
 2869
 2870    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2871        let hide_mouse_cursor = match origin {
 2872            HideMouseCursorOrigin::TypingAction => {
 2873                matches!(
 2874                    self.hide_mouse_mode,
 2875                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2876                )
 2877            }
 2878            HideMouseCursorOrigin::MovementAction => {
 2879                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2880            }
 2881        };
 2882        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2883            self.mouse_cursor_hidden = hide_mouse_cursor;
 2884            cx.notify();
 2885        }
 2886    }
 2887
 2888    pub fn edit_prediction_in_conflict(&self) -> bool {
 2889        if !self.show_edit_predictions_in_menu() {
 2890            return false;
 2891        }
 2892
 2893        let showing_completions = self
 2894            .context_menu
 2895            .borrow()
 2896            .as_ref()
 2897            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2898
 2899        showing_completions
 2900            || self.edit_prediction_requires_modifier()
 2901            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2902            // bindings to insert tab characters.
 2903            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2904    }
 2905
 2906    pub fn accept_edit_prediction_keybind(
 2907        &self,
 2908        granularity: EditPredictionGranularity,
 2909        window: &mut Window,
 2910        cx: &mut App,
 2911    ) -> AcceptEditPredictionBinding {
 2912        let key_context = self.key_context_internal(true, window, cx);
 2913        let in_conflict = self.edit_prediction_in_conflict();
 2914
 2915        let bindings =
 2916            match granularity {
 2917                EditPredictionGranularity::Word => window
 2918                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2919                EditPredictionGranularity::Line => window
 2920                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2921                EditPredictionGranularity::Full => {
 2922                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2923                }
 2924            };
 2925
 2926        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2927            !in_conflict
 2928                || binding
 2929                    .keystrokes()
 2930                    .first()
 2931                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2932        }))
 2933    }
 2934
 2935    pub fn new_file(
 2936        workspace: &mut Workspace,
 2937        _: &workspace::NewFile,
 2938        window: &mut Window,
 2939        cx: &mut Context<Workspace>,
 2940    ) {
 2941        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2942            "Failed to create buffer",
 2943            window,
 2944            cx,
 2945            |e, _, _| match e.error_code() {
 2946                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2947                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2948                e.error_tag("required").unwrap_or("the latest version")
 2949            )),
 2950                _ => None,
 2951            },
 2952        );
 2953    }
 2954
 2955    pub fn new_in_workspace(
 2956        workspace: &mut Workspace,
 2957        window: &mut Window,
 2958        cx: &mut Context<Workspace>,
 2959    ) -> Task<Result<Entity<Editor>>> {
 2960        let project = workspace.project().clone();
 2961        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 2962
 2963        cx.spawn_in(window, async move |workspace, cx| {
 2964            let buffer = create.await?;
 2965            workspace.update_in(cx, |workspace, window, cx| {
 2966                let editor =
 2967                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2968                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2969                editor
 2970            })
 2971        })
 2972    }
 2973
 2974    fn new_file_vertical(
 2975        workspace: &mut Workspace,
 2976        _: &workspace::NewFileSplitVertical,
 2977        window: &mut Window,
 2978        cx: &mut Context<Workspace>,
 2979    ) {
 2980        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2981    }
 2982
 2983    fn new_file_horizontal(
 2984        workspace: &mut Workspace,
 2985        _: &workspace::NewFileSplitHorizontal,
 2986        window: &mut Window,
 2987        cx: &mut Context<Workspace>,
 2988    ) {
 2989        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2990    }
 2991
 2992    fn new_file_split(
 2993        workspace: &mut Workspace,
 2994        action: &workspace::NewFileSplit,
 2995        window: &mut Window,
 2996        cx: &mut Context<Workspace>,
 2997    ) {
 2998        Self::new_file_in_direction(workspace, action.0, window, cx)
 2999    }
 3000
 3001    fn new_file_in_direction(
 3002        workspace: &mut Workspace,
 3003        direction: SplitDirection,
 3004        window: &mut Window,
 3005        cx: &mut Context<Workspace>,
 3006    ) {
 3007        let project = workspace.project().clone();
 3008        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3009
 3010        cx.spawn_in(window, async move |workspace, cx| {
 3011            let buffer = create.await?;
 3012            workspace.update_in(cx, move |workspace, window, cx| {
 3013                workspace.split_item(
 3014                    direction,
 3015                    Box::new(
 3016                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 3017                    ),
 3018                    window,
 3019                    cx,
 3020                )
 3021            })?;
 3022            anyhow::Ok(())
 3023        })
 3024        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 3025            match e.error_code() {
 3026                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3027                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3028                e.error_tag("required").unwrap_or("the latest version")
 3029            )),
 3030                _ => None,
 3031            }
 3032        });
 3033    }
 3034
 3035    pub fn leader_id(&self) -> Option<CollaboratorId> {
 3036        self.leader_id
 3037    }
 3038
 3039    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 3040        &self.buffer
 3041    }
 3042
 3043    pub fn project(&self) -> Option<&Entity<Project>> {
 3044        self.project.as_ref()
 3045    }
 3046
 3047    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 3048        self.workspace.as_ref()?.0.upgrade()
 3049    }
 3050
 3051    /// Returns the workspace serialization ID if this editor should be serialized.
 3052    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 3053        self.workspace
 3054            .as_ref()
 3055            .filter(|_| self.should_serialize_buffer())
 3056            .and_then(|workspace| workspace.1)
 3057    }
 3058
 3059    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 3060        self.buffer().read(cx).title(cx)
 3061    }
 3062
 3063    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 3064        let git_blame_gutter_max_author_length = self
 3065            .render_git_blame_gutter(cx)
 3066            .then(|| {
 3067                if let Some(blame) = self.blame.as_ref() {
 3068                    let max_author_length =
 3069                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 3070                    Some(max_author_length)
 3071                } else {
 3072                    None
 3073                }
 3074            })
 3075            .flatten();
 3076
 3077        EditorSnapshot {
 3078            mode: self.mode.clone(),
 3079            show_gutter: self.show_gutter,
 3080            offset_content: self.offset_content,
 3081            show_line_numbers: self.show_line_numbers,
 3082            number_deleted_lines: self.number_deleted_lines,
 3083            show_git_diff_gutter: self.show_git_diff_gutter,
 3084            show_code_actions: self.show_code_actions,
 3085            show_runnables: self.show_runnables,
 3086            show_breakpoints: self.show_breakpoints,
 3087            git_blame_gutter_max_author_length,
 3088            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 3089            placeholder_display_snapshot: self
 3090                .placeholder_display_map
 3091                .as_ref()
 3092                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 3093            scroll_anchor: self.scroll_manager.anchor(),
 3094            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 3095            is_focused: self.focus_handle.is_focused(window),
 3096            current_line_highlight: self
 3097                .current_line_highlight
 3098                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 3099            gutter_hovered: self.gutter_hovered,
 3100        }
 3101    }
 3102
 3103    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 3104        self.buffer.read(cx).language_at(point, cx)
 3105    }
 3106
 3107    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 3108        self.buffer.read(cx).read(cx).file_at(point).cloned()
 3109    }
 3110
 3111    pub fn active_excerpt(
 3112        &self,
 3113        cx: &App,
 3114    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 3115        self.buffer
 3116            .read(cx)
 3117            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 3118    }
 3119
 3120    pub fn mode(&self) -> &EditorMode {
 3121        &self.mode
 3122    }
 3123
 3124    pub fn set_mode(&mut self, mode: EditorMode) {
 3125        self.mode = mode;
 3126    }
 3127
 3128    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3129        self.collaboration_hub.as_deref()
 3130    }
 3131
 3132    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3133        self.collaboration_hub = Some(hub);
 3134    }
 3135
 3136    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3137        self.in_project_search = in_project_search;
 3138    }
 3139
 3140    pub fn set_custom_context_menu(
 3141        &mut self,
 3142        f: impl 'static
 3143        + Fn(
 3144            &mut Self,
 3145            DisplayPoint,
 3146            &mut Window,
 3147            &mut Context<Self>,
 3148        ) -> Option<Entity<ui::ContextMenu>>,
 3149    ) {
 3150        self.custom_context_menu = Some(Box::new(f))
 3151    }
 3152
 3153    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3154        self.completion_provider = provider;
 3155    }
 3156
 3157    #[cfg(any(test, feature = "test-support"))]
 3158    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3159        self.completion_provider.clone()
 3160    }
 3161
 3162    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3163        self.semantics_provider.clone()
 3164    }
 3165
 3166    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3167        self.semantics_provider = provider;
 3168    }
 3169
 3170    pub fn set_edit_prediction_provider<T>(
 3171        &mut self,
 3172        provider: Option<Entity<T>>,
 3173        window: &mut Window,
 3174        cx: &mut Context<Self>,
 3175    ) where
 3176        T: EditPredictionDelegate,
 3177    {
 3178        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3179            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3180                if this.focus_handle.is_focused(window) {
 3181                    this.update_visible_edit_prediction(window, cx);
 3182                }
 3183            }),
 3184            provider: Arc::new(provider),
 3185        });
 3186        self.update_edit_prediction_settings(cx);
 3187        self.refresh_edit_prediction(false, false, window, cx);
 3188    }
 3189
 3190    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3191        self.placeholder_display_map
 3192            .as_ref()
 3193            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3194    }
 3195
 3196    pub fn set_placeholder_text(
 3197        &mut self,
 3198        placeholder_text: &str,
 3199        window: &mut Window,
 3200        cx: &mut Context<Self>,
 3201    ) {
 3202        let multibuffer = cx
 3203            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3204
 3205        let style = window.text_style();
 3206
 3207        self.placeholder_display_map = Some(cx.new(|cx| {
 3208            DisplayMap::new(
 3209                multibuffer,
 3210                style.font(),
 3211                style.font_size.to_pixels(window.rem_size()),
 3212                None,
 3213                FILE_HEADER_HEIGHT,
 3214                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3215                Default::default(),
 3216                DiagnosticSeverity::Off,
 3217                cx,
 3218            )
 3219        }));
 3220        cx.notify();
 3221    }
 3222
 3223    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3224        self.cursor_shape = cursor_shape;
 3225
 3226        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3227        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3228
 3229        cx.notify();
 3230    }
 3231
 3232    pub fn cursor_shape(&self) -> CursorShape {
 3233        self.cursor_shape
 3234    }
 3235
 3236    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3237        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3238    }
 3239
 3240    pub fn set_current_line_highlight(
 3241        &mut self,
 3242        current_line_highlight: Option<CurrentLineHighlight>,
 3243    ) {
 3244        self.current_line_highlight = current_line_highlight;
 3245    }
 3246
 3247    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3248        self.collapse_matches = collapse_matches;
 3249    }
 3250
 3251    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3252        if self.collapse_matches {
 3253            return range.start..range.start;
 3254        }
 3255        range.clone()
 3256    }
 3257
 3258    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3259        self.display_map.read(cx).clip_at_line_ends
 3260    }
 3261
 3262    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3263        if self.display_map.read(cx).clip_at_line_ends != clip {
 3264            self.display_map
 3265                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3266        }
 3267    }
 3268
 3269    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3270        self.input_enabled = input_enabled;
 3271    }
 3272
 3273    pub fn set_edit_predictions_hidden_for_vim_mode(
 3274        &mut self,
 3275        hidden: bool,
 3276        window: &mut Window,
 3277        cx: &mut Context<Self>,
 3278    ) {
 3279        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3280            self.edit_predictions_hidden_for_vim_mode = hidden;
 3281            if hidden {
 3282                self.update_visible_edit_prediction(window, cx);
 3283            } else {
 3284                self.refresh_edit_prediction(true, false, window, cx);
 3285            }
 3286        }
 3287    }
 3288
 3289    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3290        self.menu_edit_predictions_policy = value;
 3291    }
 3292
 3293    pub fn set_autoindent(&mut self, autoindent: bool) {
 3294        if autoindent {
 3295            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3296        } else {
 3297            self.autoindent_mode = None;
 3298        }
 3299    }
 3300
 3301    pub fn capability(&self, cx: &App) -> Capability {
 3302        if self.read_only {
 3303            Capability::ReadOnly
 3304        } else {
 3305            self.buffer.read(cx).capability()
 3306        }
 3307    }
 3308
 3309    pub fn read_only(&self, cx: &App) -> bool {
 3310        self.read_only || self.buffer.read(cx).read_only()
 3311    }
 3312
 3313    pub fn set_read_only(&mut self, read_only: bool) {
 3314        self.read_only = read_only;
 3315    }
 3316
 3317    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3318        self.use_autoclose = autoclose;
 3319    }
 3320
 3321    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3322        self.use_auto_surround = auto_surround;
 3323    }
 3324
 3325    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3326        self.auto_replace_emoji_shortcode = auto_replace;
 3327    }
 3328
 3329    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3330        self.buffer_serialization = should_serialize.then(|| {
 3331            BufferSerialization::new(
 3332                ProjectSettings::get_global(cx)
 3333                    .session
 3334                    .restore_unsaved_buffers,
 3335            )
 3336        })
 3337    }
 3338
 3339    fn should_serialize_buffer(&self) -> bool {
 3340        self.buffer_serialization.is_some()
 3341    }
 3342
 3343    pub fn toggle_edit_predictions(
 3344        &mut self,
 3345        _: &ToggleEditPrediction,
 3346        window: &mut Window,
 3347        cx: &mut Context<Self>,
 3348    ) {
 3349        if self.show_edit_predictions_override.is_some() {
 3350            self.set_show_edit_predictions(None, window, cx);
 3351        } else {
 3352            let show_edit_predictions = !self.edit_predictions_enabled();
 3353            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3354        }
 3355    }
 3356
 3357    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3358        self.show_completions_on_input_override = show_completions_on_input;
 3359    }
 3360
 3361    pub fn set_show_edit_predictions(
 3362        &mut self,
 3363        show_edit_predictions: Option<bool>,
 3364        window: &mut Window,
 3365        cx: &mut Context<Self>,
 3366    ) {
 3367        self.show_edit_predictions_override = show_edit_predictions;
 3368        self.update_edit_prediction_settings(cx);
 3369
 3370        if let Some(false) = show_edit_predictions {
 3371            self.discard_edit_prediction(false, cx);
 3372        } else {
 3373            self.refresh_edit_prediction(false, true, window, cx);
 3374        }
 3375    }
 3376
 3377    fn edit_predictions_disabled_in_scope(
 3378        &self,
 3379        buffer: &Entity<Buffer>,
 3380        buffer_position: language::Anchor,
 3381        cx: &App,
 3382    ) -> bool {
 3383        let snapshot = buffer.read(cx).snapshot();
 3384        let settings = snapshot.settings_at(buffer_position, cx);
 3385
 3386        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3387            return false;
 3388        };
 3389
 3390        scope.override_name().is_some_and(|scope_name| {
 3391            settings
 3392                .edit_predictions_disabled_in
 3393                .iter()
 3394                .any(|s| s == scope_name)
 3395        })
 3396    }
 3397
 3398    pub fn set_use_modal_editing(&mut self, to: bool) {
 3399        self.use_modal_editing = to;
 3400    }
 3401
 3402    pub fn use_modal_editing(&self) -> bool {
 3403        self.use_modal_editing
 3404    }
 3405
 3406    fn selections_did_change(
 3407        &mut self,
 3408        local: bool,
 3409        old_cursor_position: &Anchor,
 3410        effects: SelectionEffects,
 3411        window: &mut Window,
 3412        cx: &mut Context<Self>,
 3413    ) {
 3414        window.invalidate_character_coordinates();
 3415
 3416        // Copy selections to primary selection buffer
 3417        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3418        if local {
 3419            let selections = self
 3420                .selections
 3421                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3422            let buffer_handle = self.buffer.read(cx).read(cx);
 3423
 3424            let mut text = String::new();
 3425            for (index, selection) in selections.iter().enumerate() {
 3426                let text_for_selection = buffer_handle
 3427                    .text_for_range(selection.start..selection.end)
 3428                    .collect::<String>();
 3429
 3430                text.push_str(&text_for_selection);
 3431                if index != selections.len() - 1 {
 3432                    text.push('\n');
 3433                }
 3434            }
 3435
 3436            if !text.is_empty() {
 3437                cx.write_to_primary(ClipboardItem::new_string(text));
 3438            }
 3439        }
 3440
 3441        let selection_anchors = self.selections.disjoint_anchors_arc();
 3442
 3443        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3444            self.buffer.update(cx, |buffer, cx| {
 3445                buffer.set_active_selections(
 3446                    &selection_anchors,
 3447                    self.selections.line_mode(),
 3448                    self.cursor_shape,
 3449                    cx,
 3450                )
 3451            });
 3452        }
 3453        let display_map = self
 3454            .display_map
 3455            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3456        let buffer = display_map.buffer_snapshot();
 3457        if self.selections.count() == 1 {
 3458            self.add_selections_state = None;
 3459        }
 3460        self.select_next_state = None;
 3461        self.select_prev_state = None;
 3462        self.select_syntax_node_history.try_clear();
 3463        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3464        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3465        self.take_rename(false, window, cx);
 3466
 3467        let newest_selection = self.selections.newest_anchor();
 3468        let new_cursor_position = newest_selection.head();
 3469        let selection_start = newest_selection.start;
 3470
 3471        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3472            self.push_to_nav_history(
 3473                *old_cursor_position,
 3474                Some(new_cursor_position.to_point(buffer)),
 3475                false,
 3476                effects.nav_history == Some(true),
 3477                cx,
 3478            );
 3479        }
 3480
 3481        if local {
 3482            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3483                self.register_buffer(buffer_id, cx);
 3484            }
 3485
 3486            let mut context_menu = self.context_menu.borrow_mut();
 3487            let completion_menu = match context_menu.as_ref() {
 3488                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3489                Some(CodeContextMenu::CodeActions(_)) => {
 3490                    *context_menu = None;
 3491                    None
 3492                }
 3493                None => None,
 3494            };
 3495            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3496            drop(context_menu);
 3497
 3498            if effects.completions
 3499                && let Some(completion_position) = completion_position
 3500            {
 3501                let start_offset = selection_start.to_offset(buffer);
 3502                let position_matches = start_offset == completion_position.to_offset(buffer);
 3503                let continue_showing = if let Some((snap, ..)) =
 3504                    buffer.point_to_buffer_offset(completion_position)
 3505                    && !snap.capability.editable()
 3506                {
 3507                    false
 3508                } else if position_matches {
 3509                    if self.snippet_stack.is_empty() {
 3510                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3511                            == Some(CharKind::Word)
 3512                    } else {
 3513                        // Snippet choices can be shown even when the cursor is in whitespace.
 3514                        // Dismissing the menu with actions like backspace is handled by
 3515                        // invalidation regions.
 3516                        true
 3517                    }
 3518                } else {
 3519                    false
 3520                };
 3521
 3522                if continue_showing {
 3523                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3524                } else {
 3525                    self.hide_context_menu(window, cx);
 3526                }
 3527            }
 3528
 3529            hide_hover(self, cx);
 3530
 3531            if old_cursor_position.to_display_point(&display_map).row()
 3532                != new_cursor_position.to_display_point(&display_map).row()
 3533            {
 3534                self.available_code_actions.take();
 3535            }
 3536            self.refresh_code_actions(window, cx);
 3537            self.refresh_document_highlights(cx);
 3538            refresh_linked_ranges(self, window, cx);
 3539
 3540            self.refresh_selected_text_highlights(false, window, cx);
 3541            self.refresh_matching_bracket_highlights(window, cx);
 3542            self.update_visible_edit_prediction(window, cx);
 3543            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3544            self.inline_blame_popover.take();
 3545            if self.git_blame_inline_enabled {
 3546                self.start_inline_blame_timer(window, cx);
 3547            }
 3548        }
 3549
 3550        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3551
 3552        if local && !self.suppress_selection_callback {
 3553            if let Some(callback) = self.on_local_selections_changed.as_ref() {
 3554                let cursor_position = self.selections.newest::<Point>(&display_map).head();
 3555                callback(cursor_position, window, cx);
 3556            }
 3557        }
 3558
 3559        cx.emit(EditorEvent::SelectionsChanged { local });
 3560
 3561        let selections = &self.selections.disjoint_anchors_arc();
 3562        if selections.len() == 1 {
 3563            cx.emit(SearchEvent::ActiveMatchChanged)
 3564        }
 3565        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3566            let inmemory_selections = selections
 3567                .iter()
 3568                .map(|s| {
 3569                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3570                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3571                })
 3572                .collect();
 3573            self.update_restoration_data(cx, |data| {
 3574                data.selections = inmemory_selections;
 3575            });
 3576
 3577            if WorkspaceSettings::get(None, cx).restore_on_startup
 3578                != RestoreOnStartupBehavior::EmptyTab
 3579                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3580            {
 3581                let snapshot = self.buffer().read(cx).snapshot(cx);
 3582                let selections = selections.clone();
 3583                let background_executor = cx.background_executor().clone();
 3584                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3585                self.serialize_selections = cx.background_spawn(async move {
 3586                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3587                    let db_selections = selections
 3588                        .iter()
 3589                        .map(|selection| {
 3590                            (
 3591                                selection.start.to_offset(&snapshot).0,
 3592                                selection.end.to_offset(&snapshot).0,
 3593                            )
 3594                        })
 3595                        .collect();
 3596
 3597                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3598                        .await
 3599                        .with_context(|| {
 3600                            format!(
 3601                                "persisting editor selections for editor {editor_id}, \
 3602                                workspace {workspace_id:?}"
 3603                            )
 3604                        })
 3605                        .log_err();
 3606                });
 3607            }
 3608        }
 3609
 3610        cx.notify();
 3611    }
 3612
 3613    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3614        use text::ToOffset as _;
 3615        use text::ToPoint as _;
 3616
 3617        if self.mode.is_minimap()
 3618            || WorkspaceSettings::get(None, cx).restore_on_startup
 3619                == RestoreOnStartupBehavior::EmptyTab
 3620        {
 3621            return;
 3622        }
 3623
 3624        if !self.buffer().read(cx).is_singleton() {
 3625            return;
 3626        }
 3627
 3628        let display_snapshot = self
 3629            .display_map
 3630            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3631        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3632            return;
 3633        };
 3634        let inmemory_folds = display_snapshot
 3635            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3636            .map(|fold| {
 3637                fold.range.start.text_anchor.to_point(&snapshot)
 3638                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3639            })
 3640            .collect();
 3641        self.update_restoration_data(cx, |data| {
 3642            data.folds = inmemory_folds;
 3643        });
 3644
 3645        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3646            return;
 3647        };
 3648        let background_executor = cx.background_executor().clone();
 3649        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3650        const FINGERPRINT_LEN: usize = 32;
 3651        let db_folds = display_snapshot
 3652            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3653            .map(|fold| {
 3654                let start = fold.range.start.text_anchor.to_offset(&snapshot);
 3655                let end = fold.range.end.text_anchor.to_offset(&snapshot);
 3656
 3657                // Extract fingerprints - content at fold boundaries for validation on restore
 3658                // Both fingerprints must be INSIDE the fold to avoid capturing surrounding
 3659                // content that might change independently.
 3660                // start_fp: first min(32, fold_len) bytes of fold content
 3661                // end_fp: last min(32, fold_len) bytes of fold content
 3662                // Clip to character boundaries to handle multibyte UTF-8 characters.
 3663                let fold_len = end - start;
 3664                let start_fp_end = snapshot
 3665                    .clip_offset(start + std::cmp::min(FINGERPRINT_LEN, fold_len), Bias::Left);
 3666                let start_fp: String = snapshot.text_for_range(start..start_fp_end).collect();
 3667                let end_fp_start = snapshot
 3668                    .clip_offset(end.saturating_sub(FINGERPRINT_LEN).max(start), Bias::Right);
 3669                let end_fp: String = snapshot.text_for_range(end_fp_start..end).collect();
 3670
 3671                (start, end, start_fp, end_fp)
 3672            })
 3673            .collect::<Vec<_>>();
 3674        self.serialize_folds = cx.background_spawn(async move {
 3675            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3676            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3677                .await
 3678                .with_context(|| {
 3679                    format!(
 3680                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3681                    )
 3682                })
 3683                .log_err();
 3684        });
 3685    }
 3686
 3687    pub fn sync_selections(
 3688        &mut self,
 3689        other: Entity<Editor>,
 3690        cx: &mut Context<Self>,
 3691    ) -> gpui::Subscription {
 3692        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3693        if !other_selections.is_empty() {
 3694            self.selections
 3695                .change_with(&self.display_snapshot(cx), |selections| {
 3696                    selections.select_anchors(other_selections);
 3697                });
 3698        }
 3699
 3700        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3701            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3702                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3703                if other_selections.is_empty() {
 3704                    return;
 3705                }
 3706                let snapshot = this.display_snapshot(cx);
 3707                this.selections.change_with(&snapshot, |selections| {
 3708                    selections.select_anchors(other_selections);
 3709                });
 3710            }
 3711        });
 3712
 3713        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3714            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3715                let these_selections = this.selections.disjoint_anchors().to_vec();
 3716                if these_selections.is_empty() {
 3717                    return;
 3718                }
 3719                other.update(cx, |other_editor, cx| {
 3720                    let snapshot = other_editor.display_snapshot(cx);
 3721                    other_editor
 3722                        .selections
 3723                        .change_with(&snapshot, |selections| {
 3724                            selections.select_anchors(these_selections);
 3725                        })
 3726                });
 3727            }
 3728        });
 3729
 3730        Subscription::join(other_subscription, this_subscription)
 3731    }
 3732
 3733    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3734        if self.buffer().read(cx).is_singleton() {
 3735            return;
 3736        }
 3737        let snapshot = self.buffer.read(cx).snapshot(cx);
 3738        let buffer_ids: HashSet<BufferId> = self
 3739            .selections
 3740            .disjoint_anchor_ranges()
 3741            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3742            .collect();
 3743        for buffer_id in buffer_ids {
 3744            self.unfold_buffer(buffer_id, cx);
 3745        }
 3746    }
 3747
 3748    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3749    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3750    /// effects of selection change occur at the end of the transaction.
 3751    pub fn change_selections<R>(
 3752        &mut self,
 3753        effects: SelectionEffects,
 3754        window: &mut Window,
 3755        cx: &mut Context<Self>,
 3756        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3757    ) -> R {
 3758        let snapshot = self.display_snapshot(cx);
 3759        if let Some(state) = &mut self.deferred_selection_effects_state {
 3760            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3761            state.effects.completions = effects.completions;
 3762            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3763            let (changed, result) = self.selections.change_with(&snapshot, change);
 3764            state.changed |= changed;
 3765            return result;
 3766        }
 3767        let mut state = DeferredSelectionEffectsState {
 3768            changed: false,
 3769            effects,
 3770            old_cursor_position: self.selections.newest_anchor().head(),
 3771            history_entry: SelectionHistoryEntry {
 3772                selections: self.selections.disjoint_anchors_arc(),
 3773                select_next_state: self.select_next_state.clone(),
 3774                select_prev_state: self.select_prev_state.clone(),
 3775                add_selections_state: self.add_selections_state.clone(),
 3776            },
 3777        };
 3778        let (changed, result) = self.selections.change_with(&snapshot, change);
 3779        state.changed = state.changed || changed;
 3780        if self.defer_selection_effects {
 3781            self.deferred_selection_effects_state = Some(state);
 3782        } else {
 3783            self.apply_selection_effects(state, window, cx);
 3784        }
 3785        result
 3786    }
 3787
 3788    /// Defers the effects of selection change, so that the effects of multiple calls to
 3789    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3790    /// to selection history and the state of popovers based on selection position aren't
 3791    /// erroneously updated.
 3792    pub fn with_selection_effects_deferred<R>(
 3793        &mut self,
 3794        window: &mut Window,
 3795        cx: &mut Context<Self>,
 3796        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3797    ) -> R {
 3798        let already_deferred = self.defer_selection_effects;
 3799        self.defer_selection_effects = true;
 3800        let result = update(self, window, cx);
 3801        if !already_deferred {
 3802            self.defer_selection_effects = false;
 3803            if let Some(state) = self.deferred_selection_effects_state.take() {
 3804                self.apply_selection_effects(state, window, cx);
 3805            }
 3806        }
 3807        result
 3808    }
 3809
 3810    fn apply_selection_effects(
 3811        &mut self,
 3812        state: DeferredSelectionEffectsState,
 3813        window: &mut Window,
 3814        cx: &mut Context<Self>,
 3815    ) {
 3816        if state.changed {
 3817            self.selection_history.push(state.history_entry);
 3818
 3819            if let Some(autoscroll) = state.effects.scroll {
 3820                self.request_autoscroll(autoscroll, cx);
 3821            }
 3822
 3823            let old_cursor_position = &state.old_cursor_position;
 3824
 3825            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3826
 3827            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3828                self.show_signature_help_auto(window, cx);
 3829            }
 3830        }
 3831    }
 3832
 3833    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3834    where
 3835        I: IntoIterator<Item = (Range<S>, T)>,
 3836        S: ToOffset,
 3837        T: Into<Arc<str>>,
 3838    {
 3839        if self.read_only(cx) {
 3840            return;
 3841        }
 3842
 3843        self.buffer
 3844            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3845    }
 3846
 3847    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3848    where
 3849        I: IntoIterator<Item = (Range<S>, T)>,
 3850        S: ToOffset,
 3851        T: Into<Arc<str>>,
 3852    {
 3853        if self.read_only(cx) {
 3854            return;
 3855        }
 3856
 3857        self.buffer.update(cx, |buffer, cx| {
 3858            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3859        });
 3860    }
 3861
 3862    pub fn edit_with_block_indent<I, S, T>(
 3863        &mut self,
 3864        edits: I,
 3865        original_indent_columns: Vec<Option<u32>>,
 3866        cx: &mut Context<Self>,
 3867    ) where
 3868        I: IntoIterator<Item = (Range<S>, T)>,
 3869        S: ToOffset,
 3870        T: Into<Arc<str>>,
 3871    {
 3872        if self.read_only(cx) {
 3873            return;
 3874        }
 3875
 3876        self.buffer.update(cx, |buffer, cx| {
 3877            buffer.edit(
 3878                edits,
 3879                Some(AutoindentMode::Block {
 3880                    original_indent_columns,
 3881                }),
 3882                cx,
 3883            )
 3884        });
 3885    }
 3886
 3887    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3888        self.hide_context_menu(window, cx);
 3889
 3890        match phase {
 3891            SelectPhase::Begin {
 3892                position,
 3893                add,
 3894                click_count,
 3895            } => self.begin_selection(position, add, click_count, window, cx),
 3896            SelectPhase::BeginColumnar {
 3897                position,
 3898                goal_column,
 3899                reset,
 3900                mode,
 3901            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3902            SelectPhase::Extend {
 3903                position,
 3904                click_count,
 3905            } => self.extend_selection(position, click_count, window, cx),
 3906            SelectPhase::Update {
 3907                position,
 3908                goal_column,
 3909                scroll_delta,
 3910            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3911            SelectPhase::End => self.end_selection(window, cx),
 3912        }
 3913    }
 3914
 3915    fn extend_selection(
 3916        &mut self,
 3917        position: DisplayPoint,
 3918        click_count: usize,
 3919        window: &mut Window,
 3920        cx: &mut Context<Self>,
 3921    ) {
 3922        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3923        let tail = self
 3924            .selections
 3925            .newest::<MultiBufferOffset>(&display_map)
 3926            .tail();
 3927        let click_count = click_count.max(match self.selections.select_mode() {
 3928            SelectMode::Character => 1,
 3929            SelectMode::Word(_) => 2,
 3930            SelectMode::Line(_) => 3,
 3931            SelectMode::All => 4,
 3932        });
 3933        self.begin_selection(position, false, click_count, window, cx);
 3934
 3935        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3936
 3937        let current_selection = match self.selections.select_mode() {
 3938            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3939            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3940        };
 3941
 3942        let mut pending_selection = self
 3943            .selections
 3944            .pending_anchor()
 3945            .cloned()
 3946            .expect("extend_selection not called with pending selection");
 3947
 3948        if pending_selection
 3949            .start
 3950            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3951            == Ordering::Greater
 3952        {
 3953            pending_selection.start = current_selection.start;
 3954        }
 3955        if pending_selection
 3956            .end
 3957            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3958            == Ordering::Less
 3959        {
 3960            pending_selection.end = current_selection.end;
 3961            pending_selection.reversed = true;
 3962        }
 3963
 3964        let mut pending_mode = self.selections.pending_mode().unwrap();
 3965        match &mut pending_mode {
 3966            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3967            _ => {}
 3968        }
 3969
 3970        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3971            SelectionEffects::scroll(Autoscroll::fit())
 3972        } else {
 3973            SelectionEffects::no_scroll()
 3974        };
 3975
 3976        self.change_selections(effects, window, cx, |s| {
 3977            s.set_pending(pending_selection.clone(), pending_mode);
 3978            s.set_is_extending(true);
 3979        });
 3980    }
 3981
 3982    fn begin_selection(
 3983        &mut self,
 3984        position: DisplayPoint,
 3985        add: bool,
 3986        click_count: usize,
 3987        window: &mut Window,
 3988        cx: &mut Context<Self>,
 3989    ) {
 3990        if !self.focus_handle.is_focused(window) {
 3991            self.last_focused_descendant = None;
 3992            window.focus(&self.focus_handle, cx);
 3993        }
 3994
 3995        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3996        let buffer = display_map.buffer_snapshot();
 3997        let position = display_map.clip_point(position, Bias::Left);
 3998
 3999        let start;
 4000        let end;
 4001        let mode;
 4002        let mut auto_scroll;
 4003        match click_count {
 4004            1 => {
 4005                start = buffer.anchor_before(position.to_point(&display_map));
 4006                end = start;
 4007                mode = SelectMode::Character;
 4008                auto_scroll = true;
 4009            }
 4010            2 => {
 4011                let position = display_map
 4012                    .clip_point(position, Bias::Left)
 4013                    .to_offset(&display_map, Bias::Left);
 4014                let (range, _) = buffer.surrounding_word(position, None);
 4015                start = buffer.anchor_before(range.start);
 4016                end = buffer.anchor_before(range.end);
 4017                mode = SelectMode::Word(start..end);
 4018                auto_scroll = true;
 4019            }
 4020            3 => {
 4021                let position = display_map
 4022                    .clip_point(position, Bias::Left)
 4023                    .to_point(&display_map);
 4024                let line_start = display_map.prev_line_boundary(position).0;
 4025                let next_line_start = buffer.clip_point(
 4026                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4027                    Bias::Left,
 4028                );
 4029                start = buffer.anchor_before(line_start);
 4030                end = buffer.anchor_before(next_line_start);
 4031                mode = SelectMode::Line(start..end);
 4032                auto_scroll = true;
 4033            }
 4034            _ => {
 4035                start = buffer.anchor_before(MultiBufferOffset(0));
 4036                end = buffer.anchor_before(buffer.len());
 4037                mode = SelectMode::All;
 4038                auto_scroll = false;
 4039            }
 4040        }
 4041        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 4042
 4043        let point_to_delete: Option<usize> = {
 4044            let selected_points: Vec<Selection<Point>> =
 4045                self.selections.disjoint_in_range(start..end, &display_map);
 4046
 4047            if !add || click_count > 1 {
 4048                None
 4049            } else if !selected_points.is_empty() {
 4050                Some(selected_points[0].id)
 4051            } else {
 4052                let clicked_point_already_selected =
 4053                    self.selections.disjoint_anchors().iter().find(|selection| {
 4054                        selection.start.to_point(buffer) == start.to_point(buffer)
 4055                            || selection.end.to_point(buffer) == end.to_point(buffer)
 4056                    });
 4057
 4058                clicked_point_already_selected.map(|selection| selection.id)
 4059            }
 4060        };
 4061
 4062        let selections_count = self.selections.count();
 4063        let effects = if auto_scroll {
 4064            SelectionEffects::default()
 4065        } else {
 4066            SelectionEffects::no_scroll()
 4067        };
 4068
 4069        self.change_selections(effects, window, cx, |s| {
 4070            if let Some(point_to_delete) = point_to_delete {
 4071                s.delete(point_to_delete);
 4072
 4073                if selections_count == 1 {
 4074                    s.set_pending_anchor_range(start..end, mode);
 4075                }
 4076            } else {
 4077                if !add {
 4078                    s.clear_disjoint();
 4079                }
 4080
 4081                s.set_pending_anchor_range(start..end, mode);
 4082            }
 4083        });
 4084    }
 4085
 4086    fn begin_columnar_selection(
 4087        &mut self,
 4088        position: DisplayPoint,
 4089        goal_column: u32,
 4090        reset: bool,
 4091        mode: ColumnarMode,
 4092        window: &mut Window,
 4093        cx: &mut Context<Self>,
 4094    ) {
 4095        if !self.focus_handle.is_focused(window) {
 4096            self.last_focused_descendant = None;
 4097            window.focus(&self.focus_handle, cx);
 4098        }
 4099
 4100        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4101
 4102        if reset {
 4103            let pointer_position = display_map
 4104                .buffer_snapshot()
 4105                .anchor_before(position.to_point(&display_map));
 4106
 4107            self.change_selections(
 4108                SelectionEffects::scroll(Autoscroll::newest()),
 4109                window,
 4110                cx,
 4111                |s| {
 4112                    s.clear_disjoint();
 4113                    s.set_pending_anchor_range(
 4114                        pointer_position..pointer_position,
 4115                        SelectMode::Character,
 4116                    );
 4117                },
 4118            );
 4119        };
 4120
 4121        let tail = self.selections.newest::<Point>(&display_map).tail();
 4122        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4123        self.columnar_selection_state = match mode {
 4124            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 4125                selection_tail: selection_anchor,
 4126                display_point: if reset {
 4127                    if position.column() != goal_column {
 4128                        Some(DisplayPoint::new(position.row(), goal_column))
 4129                    } else {
 4130                        None
 4131                    }
 4132                } else {
 4133                    None
 4134                },
 4135            }),
 4136            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 4137                selection_tail: selection_anchor,
 4138            }),
 4139        };
 4140
 4141        if !reset {
 4142            self.select_columns(position, goal_column, &display_map, window, cx);
 4143        }
 4144    }
 4145
 4146    fn update_selection(
 4147        &mut self,
 4148        position: DisplayPoint,
 4149        goal_column: u32,
 4150        scroll_delta: gpui::Point<f32>,
 4151        window: &mut Window,
 4152        cx: &mut Context<Self>,
 4153    ) {
 4154        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4155
 4156        if self.columnar_selection_state.is_some() {
 4157            self.select_columns(position, goal_column, &display_map, window, cx);
 4158        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4159            let buffer = display_map.buffer_snapshot();
 4160            let head;
 4161            let tail;
 4162            let mode = self.selections.pending_mode().unwrap();
 4163            match &mode {
 4164                SelectMode::Character => {
 4165                    head = position.to_point(&display_map);
 4166                    tail = pending.tail().to_point(buffer);
 4167                }
 4168                SelectMode::Word(original_range) => {
 4169                    let offset = display_map
 4170                        .clip_point(position, Bias::Left)
 4171                        .to_offset(&display_map, Bias::Left);
 4172                    let original_range = original_range.to_offset(buffer);
 4173
 4174                    let head_offset = if buffer.is_inside_word(offset, None)
 4175                        || original_range.contains(&offset)
 4176                    {
 4177                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4178                        if word_range.start < original_range.start {
 4179                            word_range.start
 4180                        } else {
 4181                            word_range.end
 4182                        }
 4183                    } else {
 4184                        offset
 4185                    };
 4186
 4187                    head = head_offset.to_point(buffer);
 4188                    if head_offset <= original_range.start {
 4189                        tail = original_range.end.to_point(buffer);
 4190                    } else {
 4191                        tail = original_range.start.to_point(buffer);
 4192                    }
 4193                }
 4194                SelectMode::Line(original_range) => {
 4195                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4196
 4197                    let position = display_map
 4198                        .clip_point(position, Bias::Left)
 4199                        .to_point(&display_map);
 4200                    let line_start = display_map.prev_line_boundary(position).0;
 4201                    let next_line_start = buffer.clip_point(
 4202                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4203                        Bias::Left,
 4204                    );
 4205
 4206                    if line_start < original_range.start {
 4207                        head = line_start
 4208                    } else {
 4209                        head = next_line_start
 4210                    }
 4211
 4212                    if head <= original_range.start {
 4213                        tail = original_range.end;
 4214                    } else {
 4215                        tail = original_range.start;
 4216                    }
 4217                }
 4218                SelectMode::All => {
 4219                    return;
 4220                }
 4221            };
 4222
 4223            if head < tail {
 4224                pending.start = buffer.anchor_before(head);
 4225                pending.end = buffer.anchor_before(tail);
 4226                pending.reversed = true;
 4227            } else {
 4228                pending.start = buffer.anchor_before(tail);
 4229                pending.end = buffer.anchor_before(head);
 4230                pending.reversed = false;
 4231            }
 4232
 4233            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4234                s.set_pending(pending.clone(), mode);
 4235            });
 4236        } else {
 4237            log::error!("update_selection dispatched with no pending selection");
 4238            return;
 4239        }
 4240
 4241        self.apply_scroll_delta(scroll_delta, window, cx);
 4242        cx.notify();
 4243    }
 4244
 4245    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4246        self.columnar_selection_state.take();
 4247        if let Some(pending_mode) = self.selections.pending_mode() {
 4248            let selections = self
 4249                .selections
 4250                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4251            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4252                s.select(selections);
 4253                s.clear_pending();
 4254                if s.is_extending() {
 4255                    s.set_is_extending(false);
 4256                } else {
 4257                    s.set_select_mode(pending_mode);
 4258                }
 4259            });
 4260        }
 4261    }
 4262
 4263    fn select_columns(
 4264        &mut self,
 4265        head: DisplayPoint,
 4266        goal_column: u32,
 4267        display_map: &DisplaySnapshot,
 4268        window: &mut Window,
 4269        cx: &mut Context<Self>,
 4270    ) {
 4271        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4272            return;
 4273        };
 4274
 4275        let tail = match columnar_state {
 4276            ColumnarSelectionState::FromMouse {
 4277                selection_tail,
 4278                display_point,
 4279            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4280            ColumnarSelectionState::FromSelection { selection_tail } => {
 4281                selection_tail.to_display_point(display_map)
 4282            }
 4283        };
 4284
 4285        let start_row = cmp::min(tail.row(), head.row());
 4286        let end_row = cmp::max(tail.row(), head.row());
 4287        let start_column = cmp::min(tail.column(), goal_column);
 4288        let end_column = cmp::max(tail.column(), goal_column);
 4289        let reversed = start_column < tail.column();
 4290
 4291        let selection_ranges = (start_row.0..=end_row.0)
 4292            .map(DisplayRow)
 4293            .filter_map(|row| {
 4294                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4295                    || start_column <= display_map.line_len(row))
 4296                    && !display_map.is_block_line(row)
 4297                {
 4298                    let start = display_map
 4299                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4300                        .to_point(display_map);
 4301                    let end = display_map
 4302                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4303                        .to_point(display_map);
 4304                    if reversed {
 4305                        Some(end..start)
 4306                    } else {
 4307                        Some(start..end)
 4308                    }
 4309                } else {
 4310                    None
 4311                }
 4312            })
 4313            .collect::<Vec<_>>();
 4314        if selection_ranges.is_empty() {
 4315            return;
 4316        }
 4317
 4318        let ranges = match columnar_state {
 4319            ColumnarSelectionState::FromMouse { .. } => {
 4320                let mut non_empty_ranges = selection_ranges
 4321                    .iter()
 4322                    .filter(|selection_range| selection_range.start != selection_range.end)
 4323                    .peekable();
 4324                if non_empty_ranges.peek().is_some() {
 4325                    non_empty_ranges.cloned().collect()
 4326                } else {
 4327                    selection_ranges
 4328                }
 4329            }
 4330            _ => selection_ranges,
 4331        };
 4332
 4333        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4334            s.select_ranges(ranges);
 4335        });
 4336        cx.notify();
 4337    }
 4338
 4339    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4340        self.selections
 4341            .all_adjusted(snapshot)
 4342            .iter()
 4343            .any(|selection| !selection.is_empty())
 4344    }
 4345
 4346    pub fn has_pending_nonempty_selection(&self) -> bool {
 4347        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4348            Some(Selection { start, end, .. }) => start != end,
 4349            None => false,
 4350        };
 4351
 4352        pending_nonempty_selection
 4353            || (self.columnar_selection_state.is_some()
 4354                && self.selections.disjoint_anchors().len() > 1)
 4355    }
 4356
 4357    pub fn has_pending_selection(&self) -> bool {
 4358        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4359    }
 4360
 4361    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4362        self.selection_mark_mode = false;
 4363        self.selection_drag_state = SelectionDragState::None;
 4364
 4365        if self.dismiss_menus_and_popups(true, window, cx) {
 4366            cx.notify();
 4367            return;
 4368        }
 4369        if self.clear_expanded_diff_hunks(cx) {
 4370            cx.notify();
 4371            return;
 4372        }
 4373        if self.show_git_blame_gutter {
 4374            self.show_git_blame_gutter = false;
 4375            cx.notify();
 4376            return;
 4377        }
 4378
 4379        if self.mode.is_full()
 4380            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4381        {
 4382            cx.notify();
 4383            return;
 4384        }
 4385
 4386        cx.propagate();
 4387    }
 4388
 4389    pub fn dismiss_menus_and_popups(
 4390        &mut self,
 4391        is_user_requested: bool,
 4392        window: &mut Window,
 4393        cx: &mut Context<Self>,
 4394    ) -> bool {
 4395        let mut dismissed = false;
 4396
 4397        dismissed |= self.take_rename(false, window, cx).is_some();
 4398        dismissed |= self.hide_blame_popover(true, cx);
 4399        dismissed |= hide_hover(self, cx);
 4400        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4401        dismissed |= self.hide_context_menu(window, cx).is_some();
 4402        dismissed |= self.mouse_context_menu.take().is_some();
 4403        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4404        dismissed |= self.snippet_stack.pop().is_some();
 4405        if self.diff_review_drag_state.is_some() {
 4406            self.cancel_diff_review_drag(cx);
 4407            dismissed = true;
 4408        }
 4409        if !self.diff_review_overlays.is_empty() {
 4410            self.dismiss_all_diff_review_overlays(cx);
 4411            dismissed = true;
 4412        }
 4413
 4414        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4415            self.dismiss_diagnostics(cx);
 4416            dismissed = true;
 4417        }
 4418
 4419        dismissed
 4420    }
 4421
 4422    fn linked_editing_ranges_for(
 4423        &self,
 4424        selection: Range<text::Anchor>,
 4425        cx: &App,
 4426    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4427        if self.linked_edit_ranges.is_empty() {
 4428            return None;
 4429        }
 4430        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4431            selection.end.buffer_id.and_then(|end_buffer_id| {
 4432                if selection.start.buffer_id != Some(end_buffer_id) {
 4433                    return None;
 4434                }
 4435                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4436                let snapshot = buffer.read(cx).snapshot();
 4437                self.linked_edit_ranges
 4438                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4439                    .map(|ranges| (ranges, snapshot, buffer))
 4440            })?;
 4441        use text::ToOffset as TO;
 4442        // find offset from the start of current range to current cursor position
 4443        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4444
 4445        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4446        let start_difference = start_offset - start_byte_offset;
 4447        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4448        let end_difference = end_offset - start_byte_offset;
 4449        // Current range has associated linked ranges.
 4450        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4451        for range in linked_ranges.iter() {
 4452            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4453            let end_offset = start_offset + end_difference;
 4454            let start_offset = start_offset + start_difference;
 4455            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4456                continue;
 4457            }
 4458            if self.selections.disjoint_anchor_ranges().any(|s| {
 4459                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4460                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4461                {
 4462                    return false;
 4463                }
 4464                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4465                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4466            }) {
 4467                continue;
 4468            }
 4469            let start = buffer_snapshot.anchor_after(start_offset);
 4470            let end = buffer_snapshot.anchor_after(end_offset);
 4471            linked_edits
 4472                .entry(buffer.clone())
 4473                .or_default()
 4474                .push(start..end);
 4475        }
 4476        Some(linked_edits)
 4477    }
 4478
 4479    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4480        let text: Arc<str> = text.into();
 4481
 4482        if self.read_only(cx) {
 4483            return;
 4484        }
 4485
 4486        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4487
 4488        self.unfold_buffers_with_selections(cx);
 4489
 4490        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4491        let mut bracket_inserted = false;
 4492        let mut edits = Vec::new();
 4493        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4494        let mut new_selections = Vec::with_capacity(selections.len());
 4495        let mut new_autoclose_regions = Vec::new();
 4496        let snapshot = self.buffer.read(cx).read(cx);
 4497        let mut clear_linked_edit_ranges = false;
 4498        let mut all_selections_read_only = true;
 4499        let mut has_adjacent_edits = false;
 4500        let mut in_adjacent_group = false;
 4501
 4502        let mut regions = self
 4503            .selections_with_autoclose_regions(selections, &snapshot)
 4504            .peekable();
 4505
 4506        while let Some((selection, autoclose_region)) = regions.next() {
 4507            if snapshot
 4508                .point_to_buffer_point(selection.head())
 4509                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4510            {
 4511                continue;
 4512            }
 4513            if snapshot
 4514                .point_to_buffer_point(selection.tail())
 4515                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4516            {
 4517                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4518                continue;
 4519            }
 4520            all_selections_read_only = false;
 4521
 4522            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4523                // Determine if the inserted text matches the opening or closing
 4524                // bracket of any of this language's bracket pairs.
 4525                let mut bracket_pair = None;
 4526                let mut is_bracket_pair_start = false;
 4527                let mut is_bracket_pair_end = false;
 4528                if !text.is_empty() {
 4529                    let mut bracket_pair_matching_end = None;
 4530                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4531                    //  and they are removing the character that triggered IME popup.
 4532                    for (pair, enabled) in scope.brackets() {
 4533                        if !pair.close && !pair.surround {
 4534                            continue;
 4535                        }
 4536
 4537                        if enabled && pair.start.ends_with(text.as_ref()) {
 4538                            let prefix_len = pair.start.len() - text.len();
 4539                            let preceding_text_matches_prefix = prefix_len == 0
 4540                                || (selection.start.column >= (prefix_len as u32)
 4541                                    && snapshot.contains_str_at(
 4542                                        Point::new(
 4543                                            selection.start.row,
 4544                                            selection.start.column - (prefix_len as u32),
 4545                                        ),
 4546                                        &pair.start[..prefix_len],
 4547                                    ));
 4548                            if preceding_text_matches_prefix {
 4549                                bracket_pair = Some(pair.clone());
 4550                                is_bracket_pair_start = true;
 4551                                break;
 4552                            }
 4553                        }
 4554                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4555                        {
 4556                            // take first bracket pair matching end, but don't break in case a later bracket
 4557                            // pair matches start
 4558                            bracket_pair_matching_end = Some(pair.clone());
 4559                        }
 4560                    }
 4561                    if let Some(end) = bracket_pair_matching_end
 4562                        && bracket_pair.is_none()
 4563                    {
 4564                        bracket_pair = Some(end);
 4565                        is_bracket_pair_end = true;
 4566                    }
 4567                }
 4568
 4569                if let Some(bracket_pair) = bracket_pair {
 4570                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4571                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4572                    let auto_surround =
 4573                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4574                    if selection.is_empty() {
 4575                        if is_bracket_pair_start {
 4576                            // If the inserted text is a suffix of an opening bracket and the
 4577                            // selection is preceded by the rest of the opening bracket, then
 4578                            // insert the closing bracket.
 4579                            let following_text_allows_autoclose = snapshot
 4580                                .chars_at(selection.start)
 4581                                .next()
 4582                                .is_none_or(|c| scope.should_autoclose_before(c));
 4583
 4584                            let preceding_text_allows_autoclose = selection.start.column == 0
 4585                                || snapshot
 4586                                    .reversed_chars_at(selection.start)
 4587                                    .next()
 4588                                    .is_none_or(|c| {
 4589                                        bracket_pair.start != bracket_pair.end
 4590                                            || !snapshot
 4591                                                .char_classifier_at(selection.start)
 4592                                                .is_word(c)
 4593                                    });
 4594
 4595                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4596                                && bracket_pair.start.len() == 1
 4597                            {
 4598                                let target = bracket_pair.start.chars().next().unwrap();
 4599                                let mut byte_offset = 0u32;
 4600                                let current_line_count = snapshot
 4601                                    .reversed_chars_at(selection.start)
 4602                                    .take_while(|&c| c != '\n')
 4603                                    .filter(|c| {
 4604                                        byte_offset += c.len_utf8() as u32;
 4605                                        if *c != target {
 4606                                            return false;
 4607                                        }
 4608
 4609                                        let point = Point::new(
 4610                                            selection.start.row,
 4611                                            selection.start.column.saturating_sub(byte_offset),
 4612                                        );
 4613
 4614                                        let is_enabled = snapshot
 4615                                            .language_scope_at(point)
 4616                                            .and_then(|scope| {
 4617                                                scope
 4618                                                    .brackets()
 4619                                                    .find(|(pair, _)| {
 4620                                                        pair.start == bracket_pair.start
 4621                                                    })
 4622                                                    .map(|(_, enabled)| enabled)
 4623                                            })
 4624                                            .unwrap_or(true);
 4625
 4626                                        let is_delimiter = snapshot
 4627                                            .language_scope_at(Point::new(
 4628                                                point.row,
 4629                                                point.column + 1,
 4630                                            ))
 4631                                            .and_then(|scope| {
 4632                                                scope
 4633                                                    .brackets()
 4634                                                    .find(|(pair, _)| {
 4635                                                        pair.start == bracket_pair.start
 4636                                                    })
 4637                                                    .map(|(_, enabled)| !enabled)
 4638                                            })
 4639                                            .unwrap_or(false);
 4640
 4641                                        is_enabled && !is_delimiter
 4642                                    })
 4643                                    .count();
 4644                                current_line_count % 2 == 1
 4645                            } else {
 4646                                false
 4647                            };
 4648
 4649                            if autoclose
 4650                                && bracket_pair.close
 4651                                && following_text_allows_autoclose
 4652                                && preceding_text_allows_autoclose
 4653                                && !is_closing_quote
 4654                            {
 4655                                let anchor = snapshot.anchor_before(selection.end);
 4656                                new_selections.push((selection.map(|_| anchor), text.len()));
 4657                                new_autoclose_regions.push((
 4658                                    anchor,
 4659                                    text.len(),
 4660                                    selection.id,
 4661                                    bracket_pair.clone(),
 4662                                ));
 4663                                edits.push((
 4664                                    selection.range(),
 4665                                    format!("{}{}", text, bracket_pair.end).into(),
 4666                                ));
 4667                                bracket_inserted = true;
 4668                                continue;
 4669                            }
 4670                        }
 4671
 4672                        if let Some(region) = autoclose_region {
 4673                            // If the selection is followed by an auto-inserted closing bracket,
 4674                            // then don't insert that closing bracket again; just move the selection
 4675                            // past the closing bracket.
 4676                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4677                                && text.as_ref() == region.pair.end.as_str()
 4678                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4679                            if should_skip {
 4680                                let anchor = snapshot.anchor_after(selection.end);
 4681                                new_selections
 4682                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4683                                continue;
 4684                            }
 4685                        }
 4686
 4687                        let always_treat_brackets_as_autoclosed = snapshot
 4688                            .language_settings_at(selection.start, cx)
 4689                            .always_treat_brackets_as_autoclosed;
 4690                        if always_treat_brackets_as_autoclosed
 4691                            && is_bracket_pair_end
 4692                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4693                        {
 4694                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4695                            // and the inserted text is a closing bracket and the selection is followed
 4696                            // by the closing bracket then move the selection past the closing bracket.
 4697                            let anchor = snapshot.anchor_after(selection.end);
 4698                            new_selections.push((selection.map(|_| anchor), text.len()));
 4699                            continue;
 4700                        }
 4701                    }
 4702                    // If an opening bracket is 1 character long and is typed while
 4703                    // text is selected, then surround that text with the bracket pair.
 4704                    else if auto_surround
 4705                        && bracket_pair.surround
 4706                        && is_bracket_pair_start
 4707                        && bracket_pair.start.chars().count() == 1
 4708                    {
 4709                        edits.push((selection.start..selection.start, text.clone()));
 4710                        edits.push((
 4711                            selection.end..selection.end,
 4712                            bracket_pair.end.as_str().into(),
 4713                        ));
 4714                        bracket_inserted = true;
 4715                        new_selections.push((
 4716                            Selection {
 4717                                id: selection.id,
 4718                                start: snapshot.anchor_after(selection.start),
 4719                                end: snapshot.anchor_before(selection.end),
 4720                                reversed: selection.reversed,
 4721                                goal: selection.goal,
 4722                            },
 4723                            0,
 4724                        ));
 4725                        continue;
 4726                    }
 4727                }
 4728            }
 4729
 4730            if self.auto_replace_emoji_shortcode
 4731                && selection.is_empty()
 4732                && text.as_ref().ends_with(':')
 4733                && let Some(possible_emoji_short_code) =
 4734                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4735                && !possible_emoji_short_code.is_empty()
 4736                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4737            {
 4738                let emoji_shortcode_start = Point::new(
 4739                    selection.start.row,
 4740                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4741                );
 4742
 4743                // Remove shortcode from buffer
 4744                edits.push((
 4745                    emoji_shortcode_start..selection.start,
 4746                    "".to_string().into(),
 4747                ));
 4748                new_selections.push((
 4749                    Selection {
 4750                        id: selection.id,
 4751                        start: snapshot.anchor_after(emoji_shortcode_start),
 4752                        end: snapshot.anchor_before(selection.start),
 4753                        reversed: selection.reversed,
 4754                        goal: selection.goal,
 4755                    },
 4756                    0,
 4757                ));
 4758
 4759                // Insert emoji
 4760                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4761                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4762                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4763
 4764                continue;
 4765            }
 4766
 4767            let next_is_adjacent = regions
 4768                .peek()
 4769                .is_some_and(|(next, _)| selection.end == next.start);
 4770
 4771            // If not handling any auto-close operation, then just replace the selected
 4772            // text with the given input and move the selection to the end of the
 4773            // newly inserted text.
 4774            let anchor = if in_adjacent_group || next_is_adjacent {
 4775                // After edits the right bias would shift those anchor to the next visible fragment
 4776                // but we want to resolve to the previous one
 4777                snapshot.anchor_before(selection.end)
 4778            } else {
 4779                snapshot.anchor_after(selection.end)
 4780            };
 4781
 4782            if !self.linked_edit_ranges.is_empty() {
 4783                let start_anchor = snapshot.anchor_before(selection.start);
 4784
 4785                let is_word_char = text.chars().next().is_none_or(|char| {
 4786                    let classifier = snapshot
 4787                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4788                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4789                    classifier.is_word(char)
 4790                });
 4791
 4792                if is_word_char {
 4793                    if let Some(ranges) = self
 4794                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4795                    {
 4796                        for (buffer, edits) in ranges {
 4797                            linked_edits
 4798                                .entry(buffer.clone())
 4799                                .or_default()
 4800                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4801                        }
 4802                    }
 4803                } else {
 4804                    clear_linked_edit_ranges = true;
 4805                }
 4806            }
 4807
 4808            new_selections.push((selection.map(|_| anchor), 0));
 4809            edits.push((selection.start..selection.end, text.clone()));
 4810
 4811            has_adjacent_edits |= next_is_adjacent;
 4812            in_adjacent_group = next_is_adjacent;
 4813        }
 4814
 4815        if all_selections_read_only {
 4816            return;
 4817        }
 4818
 4819        drop(regions);
 4820        drop(snapshot);
 4821
 4822        self.transact(window, cx, |this, window, cx| {
 4823            if clear_linked_edit_ranges {
 4824                this.linked_edit_ranges.clear();
 4825            }
 4826            let initial_buffer_versions =
 4827                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4828
 4829            this.buffer.update(cx, |buffer, cx| {
 4830                if has_adjacent_edits {
 4831                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 4832                } else {
 4833                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4834                }
 4835            });
 4836            for (buffer, edits) in linked_edits {
 4837                buffer.update(cx, |buffer, cx| {
 4838                    let snapshot = buffer.snapshot();
 4839                    let edits = edits
 4840                        .into_iter()
 4841                        .map(|(range, text)| {
 4842                            use text::ToPoint as TP;
 4843                            let end_point = TP::to_point(&range.end, &snapshot);
 4844                            let start_point = TP::to_point(&range.start, &snapshot);
 4845                            (start_point..end_point, text)
 4846                        })
 4847                        .sorted_by_key(|(range, _)| range.start);
 4848                    buffer.edit(edits, None, cx);
 4849                })
 4850            }
 4851            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4852            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4853            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4854            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4855                new_anchor_selections,
 4856                &map,
 4857            )
 4858            .zip(new_selection_deltas)
 4859            .map(|(selection, delta)| Selection {
 4860                id: selection.id,
 4861                start: selection.start + delta,
 4862                end: selection.end + delta,
 4863                reversed: selection.reversed,
 4864                goal: SelectionGoal::None,
 4865            })
 4866            .collect::<Vec<_>>();
 4867
 4868            let mut i = 0;
 4869            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4870                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4871                let start = map.buffer_snapshot().anchor_before(position);
 4872                let end = map.buffer_snapshot().anchor_after(position);
 4873                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4874                    match existing_state
 4875                        .range
 4876                        .start
 4877                        .cmp(&start, map.buffer_snapshot())
 4878                    {
 4879                        Ordering::Less => i += 1,
 4880                        Ordering::Greater => break,
 4881                        Ordering::Equal => {
 4882                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4883                                Ordering::Less => i += 1,
 4884                                Ordering::Equal => break,
 4885                                Ordering::Greater => break,
 4886                            }
 4887                        }
 4888                    }
 4889                }
 4890                this.autoclose_regions.insert(
 4891                    i,
 4892                    AutocloseRegion {
 4893                        selection_id,
 4894                        range: start..end,
 4895                        pair,
 4896                    },
 4897                );
 4898            }
 4899
 4900            let had_active_edit_prediction = this.has_active_edit_prediction();
 4901            this.change_selections(
 4902                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4903                window,
 4904                cx,
 4905                |s| s.select(new_selections),
 4906            );
 4907
 4908            if !bracket_inserted
 4909                && let Some(on_type_format_task) =
 4910                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4911            {
 4912                on_type_format_task.detach_and_log_err(cx);
 4913            }
 4914
 4915            let editor_settings = EditorSettings::get_global(cx);
 4916            if bracket_inserted
 4917                && (editor_settings.auto_signature_help
 4918                    || editor_settings.show_signature_help_after_edits)
 4919            {
 4920                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4921            }
 4922
 4923            let trigger_in_words =
 4924                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4925            if this.hard_wrap.is_some() {
 4926                let latest: Range<Point> = this.selections.newest(&map).range();
 4927                if latest.is_empty()
 4928                    && this
 4929                        .buffer()
 4930                        .read(cx)
 4931                        .snapshot(cx)
 4932                        .line_len(MultiBufferRow(latest.start.row))
 4933                        == latest.start.column
 4934                {
 4935                    this.rewrap_impl(
 4936                        RewrapOptions {
 4937                            override_language_settings: true,
 4938                            preserve_existing_whitespace: true,
 4939                        },
 4940                        cx,
 4941                    )
 4942                }
 4943            }
 4944            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4945            refresh_linked_ranges(this, window, cx);
 4946            this.refresh_edit_prediction(true, false, window, cx);
 4947            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4948        });
 4949    }
 4950
 4951    fn find_possible_emoji_shortcode_at_position(
 4952        snapshot: &MultiBufferSnapshot,
 4953        position: Point,
 4954    ) -> Option<String> {
 4955        let mut chars = Vec::new();
 4956        let mut found_colon = false;
 4957        for char in snapshot.reversed_chars_at(position).take(100) {
 4958            // Found a possible emoji shortcode in the middle of the buffer
 4959            if found_colon {
 4960                if char.is_whitespace() {
 4961                    chars.reverse();
 4962                    return Some(chars.iter().collect());
 4963                }
 4964                // If the previous character is not a whitespace, we are in the middle of a word
 4965                // and we only want to complete the shortcode if the word is made up of other emojis
 4966                let mut containing_word = String::new();
 4967                for ch in snapshot
 4968                    .reversed_chars_at(position)
 4969                    .skip(chars.len() + 1)
 4970                    .take(100)
 4971                {
 4972                    if ch.is_whitespace() {
 4973                        break;
 4974                    }
 4975                    containing_word.push(ch);
 4976                }
 4977                let containing_word = containing_word.chars().rev().collect::<String>();
 4978                if util::word_consists_of_emojis(containing_word.as_str()) {
 4979                    chars.reverse();
 4980                    return Some(chars.iter().collect());
 4981                }
 4982            }
 4983
 4984            if char.is_whitespace() || !char.is_ascii() {
 4985                return None;
 4986            }
 4987            if char == ':' {
 4988                found_colon = true;
 4989            } else {
 4990                chars.push(char);
 4991            }
 4992        }
 4993        // Found a possible emoji shortcode at the beginning of the buffer
 4994        chars.reverse();
 4995        Some(chars.iter().collect())
 4996    }
 4997
 4998    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4999        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5000        self.transact(window, cx, |this, window, cx| {
 5001            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 5002                let selections = this
 5003                    .selections
 5004                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 5005                let multi_buffer = this.buffer.read(cx);
 5006                let buffer = multi_buffer.snapshot(cx);
 5007                selections
 5008                    .iter()
 5009                    .map(|selection| {
 5010                        let start_point = selection.start.to_point(&buffer);
 5011                        let mut existing_indent =
 5012                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 5013                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 5014                        let start = selection.start;
 5015                        let end = selection.end;
 5016                        let selection_is_empty = start == end;
 5017                        let language_scope = buffer.language_scope_at(start);
 5018                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 5019                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 5020                                &buffer,
 5021                                start..end,
 5022                                language,
 5023                            )
 5024                                || NewlineConfig::insert_extra_newline_tree_sitter(
 5025                                    &buffer,
 5026                                    start..end,
 5027                                );
 5028
 5029                            let mut newline_config = NewlineConfig::Newline {
 5030                                additional_indent: IndentSize::spaces(0),
 5031                                extra_line_additional_indent: if needs_extra_newline {
 5032                                    Some(IndentSize::spaces(0))
 5033                                } else {
 5034                                    None
 5035                                },
 5036                                prevent_auto_indent: false,
 5037                            };
 5038
 5039                            let comment_delimiter = maybe!({
 5040                                if !selection_is_empty {
 5041                                    return None;
 5042                                }
 5043
 5044                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5045                                    return None;
 5046                                }
 5047
 5048                                return comment_delimiter_for_newline(
 5049                                    &start_point,
 5050                                    &buffer,
 5051                                    language,
 5052                                );
 5053                            });
 5054
 5055                            let doc_delimiter = maybe!({
 5056                                if !selection_is_empty {
 5057                                    return None;
 5058                                }
 5059
 5060                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5061                                    return None;
 5062                                }
 5063
 5064                                return documentation_delimiter_for_newline(
 5065                                    &start_point,
 5066                                    &buffer,
 5067                                    language,
 5068                                    &mut newline_config,
 5069                                );
 5070                            });
 5071
 5072                            let list_delimiter = maybe!({
 5073                                if !selection_is_empty {
 5074                                    return None;
 5075                                }
 5076
 5077                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 5078                                    return None;
 5079                                }
 5080
 5081                                return list_delimiter_for_newline(
 5082                                    &start_point,
 5083                                    &buffer,
 5084                                    language,
 5085                                    &mut newline_config,
 5086                                );
 5087                            });
 5088
 5089                            (
 5090                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 5091                                newline_config,
 5092                            )
 5093                        } else {
 5094                            (
 5095                                None,
 5096                                NewlineConfig::Newline {
 5097                                    additional_indent: IndentSize::spaces(0),
 5098                                    extra_line_additional_indent: None,
 5099                                    prevent_auto_indent: false,
 5100                                },
 5101                            )
 5102                        };
 5103
 5104                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 5105                            NewlineConfig::ClearCurrentLine => {
 5106                                let row_start =
 5107                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5108                                (row_start, String::new(), false)
 5109                            }
 5110                            NewlineConfig::UnindentCurrentLine { continuation } => {
 5111                                let row_start =
 5112                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5113                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 5114                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 5115                                let reduced_indent =
 5116                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 5117                                let mut new_text = String::new();
 5118                                new_text.extend(reduced_indent.chars());
 5119                                new_text.push_str(continuation);
 5120                                (row_start, new_text, true)
 5121                            }
 5122                            NewlineConfig::Newline {
 5123                                additional_indent,
 5124                                extra_line_additional_indent,
 5125                                prevent_auto_indent,
 5126                            } => {
 5127                                let capacity_for_delimiter =
 5128                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 5129                                let extra_line_len = extra_line_additional_indent
 5130                                    .map(|i| 1 + existing_indent.len as usize + i.len as usize)
 5131                                    .unwrap_or(0);
 5132                                let mut new_text = String::with_capacity(
 5133                                    1 + capacity_for_delimiter
 5134                                        + existing_indent.len as usize
 5135                                        + additional_indent.len as usize
 5136                                        + extra_line_len,
 5137                                );
 5138                                new_text.push('\n');
 5139                                new_text.extend(existing_indent.chars());
 5140                                new_text.extend(additional_indent.chars());
 5141                                if let Some(delimiter) = &delimiter {
 5142                                    new_text.push_str(delimiter);
 5143                                }
 5144                                if let Some(extra_indent) = extra_line_additional_indent {
 5145                                    new_text.push('\n');
 5146                                    new_text.extend(existing_indent.chars());
 5147                                    new_text.extend(extra_indent.chars());
 5148                                }
 5149                                (start, new_text, *prevent_auto_indent)
 5150                            }
 5151                        };
 5152
 5153                        let anchor = buffer.anchor_after(end);
 5154                        let new_selection = selection.map(|_| anchor);
 5155                        (
 5156                            ((edit_start..end, new_text), prevent_auto_indent),
 5157                            (newline_config.has_extra_line(), new_selection),
 5158                        )
 5159                    })
 5160                    .unzip()
 5161            };
 5162
 5163            let mut auto_indent_edits = Vec::new();
 5164            let mut edits = Vec::new();
 5165            for (edit, prevent_auto_indent) in edits_with_flags {
 5166                if prevent_auto_indent {
 5167                    edits.push(edit);
 5168                } else {
 5169                    auto_indent_edits.push(edit);
 5170                }
 5171            }
 5172            if !edits.is_empty() {
 5173                this.edit(edits, cx);
 5174            }
 5175            if !auto_indent_edits.is_empty() {
 5176                this.edit_with_autoindent(auto_indent_edits, cx);
 5177            }
 5178
 5179            let buffer = this.buffer.read(cx).snapshot(cx);
 5180            let new_selections = selection_info
 5181                .into_iter()
 5182                .map(|(extra_newline_inserted, new_selection)| {
 5183                    let mut cursor = new_selection.end.to_point(&buffer);
 5184                    if extra_newline_inserted {
 5185                        cursor.row -= 1;
 5186                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5187                    }
 5188                    new_selection.map(|_| cursor)
 5189                })
 5190                .collect();
 5191
 5192            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5193            this.refresh_edit_prediction(true, false, window, cx);
 5194            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5195                task.detach_and_log_err(cx);
 5196            }
 5197        });
 5198    }
 5199
 5200    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5201        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5202
 5203        let buffer = self.buffer.read(cx);
 5204        let snapshot = buffer.snapshot(cx);
 5205
 5206        let mut edits = Vec::new();
 5207        let mut rows = Vec::new();
 5208
 5209        for (rows_inserted, selection) in self
 5210            .selections
 5211            .all_adjusted(&self.display_snapshot(cx))
 5212            .into_iter()
 5213            .enumerate()
 5214        {
 5215            let cursor = selection.head();
 5216            let row = cursor.row;
 5217
 5218            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5219
 5220            let newline = "\n".to_string();
 5221            edits.push((start_of_line..start_of_line, newline));
 5222
 5223            rows.push(row + rows_inserted as u32);
 5224        }
 5225
 5226        self.transact(window, cx, |editor, window, cx| {
 5227            editor.edit(edits, cx);
 5228
 5229            editor.change_selections(Default::default(), window, cx, |s| {
 5230                let mut index = 0;
 5231                s.move_cursors_with(|map, _, _| {
 5232                    let row = rows[index];
 5233                    index += 1;
 5234
 5235                    let point = Point::new(row, 0);
 5236                    let boundary = map.next_line_boundary(point).1;
 5237                    let clipped = map.clip_point(boundary, Bias::Left);
 5238
 5239                    (clipped, SelectionGoal::None)
 5240                });
 5241            });
 5242
 5243            let mut indent_edits = Vec::new();
 5244            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5245            for row in rows {
 5246                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5247                for (row, indent) in indents {
 5248                    if indent.len == 0 {
 5249                        continue;
 5250                    }
 5251
 5252                    let text = match indent.kind {
 5253                        IndentKind::Space => " ".repeat(indent.len as usize),
 5254                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5255                    };
 5256                    let point = Point::new(row.0, 0);
 5257                    indent_edits.push((point..point, text));
 5258                }
 5259            }
 5260            editor.edit(indent_edits, cx);
 5261            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5262                format.detach_and_log_err(cx);
 5263            }
 5264        });
 5265    }
 5266
 5267    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5268        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5269
 5270        let buffer = self.buffer.read(cx);
 5271        let snapshot = buffer.snapshot(cx);
 5272
 5273        let mut edits = Vec::new();
 5274        let mut rows = Vec::new();
 5275        let mut rows_inserted = 0;
 5276
 5277        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5278            let cursor = selection.head();
 5279            let row = cursor.row;
 5280
 5281            let point = Point::new(row + 1, 0);
 5282            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5283
 5284            let newline = "\n".to_string();
 5285            edits.push((start_of_line..start_of_line, newline));
 5286
 5287            rows_inserted += 1;
 5288            rows.push(row + rows_inserted);
 5289        }
 5290
 5291        self.transact(window, cx, |editor, window, cx| {
 5292            editor.edit(edits, cx);
 5293
 5294            editor.change_selections(Default::default(), window, cx, |s| {
 5295                let mut index = 0;
 5296                s.move_cursors_with(|map, _, _| {
 5297                    let row = rows[index];
 5298                    index += 1;
 5299
 5300                    let point = Point::new(row, 0);
 5301                    let boundary = map.next_line_boundary(point).1;
 5302                    let clipped = map.clip_point(boundary, Bias::Left);
 5303
 5304                    (clipped, SelectionGoal::None)
 5305                });
 5306            });
 5307
 5308            let mut indent_edits = Vec::new();
 5309            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5310            for row in rows {
 5311                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5312                for (row, indent) in indents {
 5313                    if indent.len == 0 {
 5314                        continue;
 5315                    }
 5316
 5317                    let text = match indent.kind {
 5318                        IndentKind::Space => " ".repeat(indent.len as usize),
 5319                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5320                    };
 5321                    let point = Point::new(row.0, 0);
 5322                    indent_edits.push((point..point, text));
 5323                }
 5324            }
 5325            editor.edit(indent_edits, cx);
 5326            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5327                format.detach_and_log_err(cx);
 5328            }
 5329        });
 5330    }
 5331
 5332    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5333        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5334            original_indent_columns: Vec::new(),
 5335        });
 5336        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5337    }
 5338
 5339    fn insert_with_autoindent_mode(
 5340        &mut self,
 5341        text: &str,
 5342        autoindent_mode: Option<AutoindentMode>,
 5343        window: &mut Window,
 5344        cx: &mut Context<Self>,
 5345    ) {
 5346        if self.read_only(cx) {
 5347            return;
 5348        }
 5349
 5350        let text: Arc<str> = text.into();
 5351        self.transact(window, cx, |this, window, cx| {
 5352            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5353            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5354                let anchors = {
 5355                    let snapshot = buffer.read(cx);
 5356                    old_selections
 5357                        .iter()
 5358                        .map(|s| {
 5359                            let anchor = snapshot.anchor_after(s.head());
 5360                            s.map(|_| anchor)
 5361                        })
 5362                        .collect::<Vec<_>>()
 5363                };
 5364                buffer.edit(
 5365                    old_selections
 5366                        .iter()
 5367                        .map(|s| (s.start..s.end, text.clone())),
 5368                    autoindent_mode,
 5369                    cx,
 5370                );
 5371                anchors
 5372            });
 5373
 5374            this.change_selections(Default::default(), window, cx, |s| {
 5375                s.select_anchors(selection_anchors);
 5376            });
 5377
 5378            cx.notify();
 5379        });
 5380    }
 5381
 5382    fn trigger_completion_on_input(
 5383        &mut self,
 5384        text: &str,
 5385        trigger_in_words: bool,
 5386        window: &mut Window,
 5387        cx: &mut Context<Self>,
 5388    ) {
 5389        let completions_source = self
 5390            .context_menu
 5391            .borrow()
 5392            .as_ref()
 5393            .and_then(|menu| match menu {
 5394                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5395                CodeContextMenu::CodeActions(_) => None,
 5396            });
 5397
 5398        match completions_source {
 5399            Some(CompletionsMenuSource::Words { .. }) => {
 5400                self.open_or_update_completions_menu(
 5401                    Some(CompletionsMenuSource::Words {
 5402                        ignore_threshold: false,
 5403                    }),
 5404                    None,
 5405                    trigger_in_words,
 5406                    window,
 5407                    cx,
 5408                );
 5409            }
 5410            _ => self.open_or_update_completions_menu(
 5411                None,
 5412                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5413                true,
 5414                window,
 5415                cx,
 5416            ),
 5417        }
 5418    }
 5419
 5420    /// If any empty selections is touching the start of its innermost containing autoclose
 5421    /// region, expand it to select the brackets.
 5422    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5423        let selections = self
 5424            .selections
 5425            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5426        let buffer = self.buffer.read(cx).read(cx);
 5427        let new_selections = self
 5428            .selections_with_autoclose_regions(selections, &buffer)
 5429            .map(|(mut selection, region)| {
 5430                if !selection.is_empty() {
 5431                    return selection;
 5432                }
 5433
 5434                if let Some(region) = region {
 5435                    let mut range = region.range.to_offset(&buffer);
 5436                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5437                        range.start -= region.pair.start.len();
 5438                        if buffer.contains_str_at(range.start, &region.pair.start)
 5439                            && buffer.contains_str_at(range.end, &region.pair.end)
 5440                        {
 5441                            range.end += region.pair.end.len();
 5442                            selection.start = range.start;
 5443                            selection.end = range.end;
 5444
 5445                            return selection;
 5446                        }
 5447                    }
 5448                }
 5449
 5450                let always_treat_brackets_as_autoclosed = buffer
 5451                    .language_settings_at(selection.start, cx)
 5452                    .always_treat_brackets_as_autoclosed;
 5453
 5454                if !always_treat_brackets_as_autoclosed {
 5455                    return selection;
 5456                }
 5457
 5458                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5459                    for (pair, enabled) in scope.brackets() {
 5460                        if !enabled || !pair.close {
 5461                            continue;
 5462                        }
 5463
 5464                        if buffer.contains_str_at(selection.start, &pair.end) {
 5465                            let pair_start_len = pair.start.len();
 5466                            if buffer.contains_str_at(
 5467                                selection.start.saturating_sub_usize(pair_start_len),
 5468                                &pair.start,
 5469                            ) {
 5470                                selection.start -= pair_start_len;
 5471                                selection.end += pair.end.len();
 5472
 5473                                return selection;
 5474                            }
 5475                        }
 5476                    }
 5477                }
 5478
 5479                selection
 5480            })
 5481            .collect();
 5482
 5483        drop(buffer);
 5484        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5485            selections.select(new_selections)
 5486        });
 5487    }
 5488
 5489    /// Iterate the given selections, and for each one, find the smallest surrounding
 5490    /// autoclose region. This uses the ordering of the selections and the autoclose
 5491    /// regions to avoid repeated comparisons.
 5492    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5493        &'a self,
 5494        selections: impl IntoIterator<Item = Selection<D>>,
 5495        buffer: &'a MultiBufferSnapshot,
 5496    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5497        let mut i = 0;
 5498        let mut regions = self.autoclose_regions.as_slice();
 5499        selections.into_iter().map(move |selection| {
 5500            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5501
 5502            let mut enclosing = None;
 5503            while let Some(pair_state) = regions.get(i) {
 5504                if pair_state.range.end.to_offset(buffer) < range.start {
 5505                    regions = &regions[i + 1..];
 5506                    i = 0;
 5507                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5508                    break;
 5509                } else {
 5510                    if pair_state.selection_id == selection.id {
 5511                        enclosing = Some(pair_state);
 5512                    }
 5513                    i += 1;
 5514                }
 5515            }
 5516
 5517            (selection, enclosing)
 5518        })
 5519    }
 5520
 5521    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5522    fn invalidate_autoclose_regions(
 5523        &mut self,
 5524        mut selections: &[Selection<Anchor>],
 5525        buffer: &MultiBufferSnapshot,
 5526    ) {
 5527        self.autoclose_regions.retain(|state| {
 5528            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5529                return false;
 5530            }
 5531
 5532            let mut i = 0;
 5533            while let Some(selection) = selections.get(i) {
 5534                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5535                    selections = &selections[1..];
 5536                    continue;
 5537                }
 5538                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5539                    break;
 5540                }
 5541                if selection.id == state.selection_id {
 5542                    return true;
 5543                } else {
 5544                    i += 1;
 5545                }
 5546            }
 5547            false
 5548        });
 5549    }
 5550
 5551    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5552        let offset = position.to_offset(buffer);
 5553        let (word_range, kind) =
 5554            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5555        if offset > word_range.start && kind == Some(CharKind::Word) {
 5556            Some(
 5557                buffer
 5558                    .text_for_range(word_range.start..offset)
 5559                    .collect::<String>(),
 5560            )
 5561        } else {
 5562            None
 5563        }
 5564    }
 5565
 5566    pub fn visible_excerpts(
 5567        &self,
 5568        lsp_related_only: bool,
 5569        cx: &mut Context<Editor>,
 5570    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5571        let project = self.project().cloned();
 5572        let multi_buffer = self.buffer().read(cx);
 5573        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5574        let multi_buffer_visible_start = self
 5575            .scroll_manager
 5576            .anchor()
 5577            .anchor
 5578            .to_point(&multi_buffer_snapshot);
 5579        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5580            multi_buffer_visible_start
 5581                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5582            Bias::Left,
 5583        );
 5584        multi_buffer_snapshot
 5585            .range_to_buffer_ranges(multi_buffer_visible_start..=multi_buffer_visible_end)
 5586            .into_iter()
 5587            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5588            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5589                if !lsp_related_only {
 5590                    return Some((
 5591                        excerpt_id,
 5592                        (
 5593                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5594                            buffer.version().clone(),
 5595                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5596                        ),
 5597                    ));
 5598                }
 5599
 5600                let project = project.as_ref()?.read(cx);
 5601                let buffer_file = project::File::from_dyn(buffer.file())?;
 5602                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5603                let worktree_entry = buffer_worktree
 5604                    .read(cx)
 5605                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5606                if worktree_entry.is_ignored {
 5607                    None
 5608                } else {
 5609                    Some((
 5610                        excerpt_id,
 5611                        (
 5612                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5613                            buffer.version().clone(),
 5614                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5615                        ),
 5616                    ))
 5617                }
 5618            })
 5619            .collect()
 5620    }
 5621
 5622    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5623        TextLayoutDetails {
 5624            text_system: window.text_system().clone(),
 5625            editor_style: self.style.clone().unwrap(),
 5626            rem_size: window.rem_size(),
 5627            scroll_anchor: self.scroll_manager.anchor(),
 5628            visible_rows: self.visible_line_count(),
 5629            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5630        }
 5631    }
 5632
 5633    fn trigger_on_type_formatting(
 5634        &self,
 5635        input: String,
 5636        window: &mut Window,
 5637        cx: &mut Context<Self>,
 5638    ) -> Option<Task<Result<()>>> {
 5639        if input.chars().count() != 1 {
 5640            return None;
 5641        }
 5642
 5643        let project = self.project()?;
 5644        let position = self.selections.newest_anchor().head();
 5645        let (buffer, buffer_position) = self
 5646            .buffer
 5647            .read(cx)
 5648            .text_anchor_for_position(position, cx)?;
 5649
 5650        let settings = language_settings::language_settings(
 5651            buffer
 5652                .read(cx)
 5653                .language_at(buffer_position)
 5654                .map(|l| l.name()),
 5655            buffer.read(cx).file(),
 5656            cx,
 5657        );
 5658        if !settings.use_on_type_format {
 5659            return None;
 5660        }
 5661
 5662        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5663        // hence we do LSP request & edit on host side only — add formats to host's history.
 5664        let push_to_lsp_host_history = true;
 5665        // If this is not the host, append its history with new edits.
 5666        let push_to_client_history = project.read(cx).is_via_collab();
 5667
 5668        let on_type_formatting = project.update(cx, |project, cx| {
 5669            project.on_type_format(
 5670                buffer.clone(),
 5671                buffer_position,
 5672                input,
 5673                push_to_lsp_host_history,
 5674                cx,
 5675            )
 5676        });
 5677        Some(cx.spawn_in(window, async move |editor, cx| {
 5678            if let Some(transaction) = on_type_formatting.await? {
 5679                if push_to_client_history {
 5680                    buffer.update(cx, |buffer, _| {
 5681                        buffer.push_transaction(transaction, Instant::now());
 5682                        buffer.finalize_last_transaction();
 5683                    });
 5684                }
 5685                editor.update(cx, |editor, cx| {
 5686                    editor.refresh_document_highlights(cx);
 5687                })?;
 5688            }
 5689            Ok(())
 5690        }))
 5691    }
 5692
 5693    pub fn show_word_completions(
 5694        &mut self,
 5695        _: &ShowWordCompletions,
 5696        window: &mut Window,
 5697        cx: &mut Context<Self>,
 5698    ) {
 5699        self.open_or_update_completions_menu(
 5700            Some(CompletionsMenuSource::Words {
 5701                ignore_threshold: true,
 5702            }),
 5703            None,
 5704            false,
 5705            window,
 5706            cx,
 5707        );
 5708    }
 5709
 5710    pub fn show_completions(
 5711        &mut self,
 5712        _: &ShowCompletions,
 5713        window: &mut Window,
 5714        cx: &mut Context<Self>,
 5715    ) {
 5716        self.open_or_update_completions_menu(None, None, false, window, cx);
 5717    }
 5718
 5719    fn open_or_update_completions_menu(
 5720        &mut self,
 5721        requested_source: Option<CompletionsMenuSource>,
 5722        trigger: Option<String>,
 5723        trigger_in_words: bool,
 5724        window: &mut Window,
 5725        cx: &mut Context<Self>,
 5726    ) {
 5727        if self.pending_rename.is_some() {
 5728            return;
 5729        }
 5730
 5731        let completions_source = self
 5732            .context_menu
 5733            .borrow()
 5734            .as_ref()
 5735            .and_then(|menu| match menu {
 5736                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5737                CodeContextMenu::CodeActions(_) => None,
 5738            });
 5739
 5740        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5741
 5742        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5743        // inserted and selected. To handle that case, the start of the selection is used so that
 5744        // the menu starts with all choices.
 5745        let position = self
 5746            .selections
 5747            .newest_anchor()
 5748            .start
 5749            .bias_right(&multibuffer_snapshot);
 5750        if position.diff_base_anchor.is_some() {
 5751            return;
 5752        }
 5753        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5754        let Some(buffer) = buffer_position
 5755            .text_anchor
 5756            .buffer_id
 5757            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5758        else {
 5759            return;
 5760        };
 5761        let buffer_snapshot = buffer.read(cx).snapshot();
 5762
 5763        let menu_is_open = matches!(
 5764            self.context_menu.borrow().as_ref(),
 5765            Some(CodeContextMenu::Completions(_))
 5766        );
 5767
 5768        let language = buffer_snapshot
 5769            .language_at(buffer_position.text_anchor)
 5770            .map(|language| language.name());
 5771
 5772        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5773        let completion_settings = language_settings.completions.clone();
 5774
 5775        let show_completions_on_input = self
 5776            .show_completions_on_input_override
 5777            .unwrap_or(language_settings.show_completions_on_input);
 5778        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5779            return;
 5780        }
 5781
 5782        let query: Option<Arc<String>> =
 5783            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5784                .map(|query| query.into());
 5785
 5786        drop(multibuffer_snapshot);
 5787
 5788        // Hide the current completions menu when query is empty. Without this, cached
 5789        // completions from before the trigger char may be reused (#32774).
 5790        if query.is_none() && menu_is_open {
 5791            self.hide_context_menu(window, cx);
 5792        }
 5793
 5794        let mut ignore_word_threshold = false;
 5795        let provider = match requested_source {
 5796            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5797            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5798                ignore_word_threshold = ignore_threshold;
 5799                None
 5800            }
 5801            Some(CompletionsMenuSource::SnippetChoices)
 5802            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5803                log::error!("bug: SnippetChoices requested_source is not handled");
 5804                None
 5805            }
 5806        };
 5807
 5808        let sort_completions = provider
 5809            .as_ref()
 5810            .is_some_and(|provider| provider.sort_completions());
 5811
 5812        let filter_completions = provider
 5813            .as_ref()
 5814            .is_none_or(|provider| provider.filter_completions());
 5815
 5816        let was_snippets_only = matches!(
 5817            completions_source,
 5818            Some(CompletionsMenuSource::SnippetsOnly)
 5819        );
 5820
 5821        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5822            if filter_completions {
 5823                menu.filter(
 5824                    query.clone().unwrap_or_default(),
 5825                    buffer_position.text_anchor,
 5826                    &buffer,
 5827                    provider.clone(),
 5828                    window,
 5829                    cx,
 5830                );
 5831            }
 5832            // When `is_incomplete` is false, no need to re-query completions when the current query
 5833            // is a suffix of the initial query.
 5834            let was_complete = !menu.is_incomplete;
 5835            if was_complete && !was_snippets_only {
 5836                // If the new query is a suffix of the old query (typing more characters) and
 5837                // the previous result was complete, the existing completions can be filtered.
 5838                //
 5839                // Note that snippet completions are always complete.
 5840                let query_matches = match (&menu.initial_query, &query) {
 5841                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5842                    (None, _) => true,
 5843                    _ => false,
 5844                };
 5845                if query_matches {
 5846                    let position_matches = if menu.initial_position == position {
 5847                        true
 5848                    } else {
 5849                        let snapshot = self.buffer.read(cx).read(cx);
 5850                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5851                    };
 5852                    if position_matches {
 5853                        return;
 5854                    }
 5855                }
 5856            }
 5857        };
 5858
 5859        let Anchor {
 5860            excerpt_id: buffer_excerpt_id,
 5861            text_anchor: buffer_position,
 5862            ..
 5863        } = buffer_position;
 5864
 5865        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5866            buffer_snapshot.surrounding_word(buffer_position, None)
 5867        {
 5868            let word_to_exclude = buffer_snapshot
 5869                .text_for_range(word_range.clone())
 5870                .collect::<String>();
 5871            (
 5872                buffer_snapshot.anchor_before(word_range.start)
 5873                    ..buffer_snapshot.anchor_after(buffer_position),
 5874                Some(word_to_exclude),
 5875            )
 5876        } else {
 5877            (buffer_position..buffer_position, None)
 5878        };
 5879
 5880        let show_completion_documentation = buffer_snapshot
 5881            .settings_at(buffer_position, cx)
 5882            .show_completion_documentation;
 5883
 5884        // The document can be large, so stay in reasonable bounds when searching for words,
 5885        // otherwise completion pop-up might be slow to appear.
 5886        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5887        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5888        let min_word_search = buffer_snapshot.clip_point(
 5889            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5890            Bias::Left,
 5891        );
 5892        let max_word_search = buffer_snapshot.clip_point(
 5893            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5894            Bias::Right,
 5895        );
 5896        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5897            ..buffer_snapshot.point_to_offset(max_word_search);
 5898
 5899        let skip_digits = query
 5900            .as_ref()
 5901            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5902
 5903        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5904            trigger.as_ref().is_none_or(|trigger| {
 5905                provider.is_completion_trigger(
 5906                    &buffer,
 5907                    position.text_anchor,
 5908                    trigger,
 5909                    trigger_in_words,
 5910                    cx,
 5911                )
 5912            })
 5913        });
 5914
 5915        let provider_responses = if let Some(provider) = &provider
 5916            && load_provider_completions
 5917        {
 5918            let trigger_character =
 5919                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5920            let completion_context = CompletionContext {
 5921                trigger_kind: match &trigger_character {
 5922                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5923                    None => CompletionTriggerKind::INVOKED,
 5924                },
 5925                trigger_character,
 5926            };
 5927
 5928            provider.completions(
 5929                buffer_excerpt_id,
 5930                &buffer,
 5931                buffer_position,
 5932                completion_context,
 5933                window,
 5934                cx,
 5935            )
 5936        } else {
 5937            Task::ready(Ok(Vec::new()))
 5938        };
 5939
 5940        let load_word_completions = if !self.word_completions_enabled {
 5941            false
 5942        } else if requested_source
 5943            == Some(CompletionsMenuSource::Words {
 5944                ignore_threshold: true,
 5945            })
 5946        {
 5947            true
 5948        } else {
 5949            load_provider_completions
 5950                && completion_settings.words != WordsCompletionMode::Disabled
 5951                && (ignore_word_threshold || {
 5952                    let words_min_length = completion_settings.words_min_length;
 5953                    // check whether word has at least `words_min_length` characters
 5954                    let query_chars = query.iter().flat_map(|q| q.chars());
 5955                    query_chars.take(words_min_length).count() == words_min_length
 5956                })
 5957        };
 5958
 5959        let mut words = if load_word_completions {
 5960            cx.background_spawn({
 5961                let buffer_snapshot = buffer_snapshot.clone();
 5962                async move {
 5963                    buffer_snapshot.words_in_range(WordsQuery {
 5964                        fuzzy_contents: None,
 5965                        range: word_search_range,
 5966                        skip_digits,
 5967                    })
 5968                }
 5969            })
 5970        } else {
 5971            Task::ready(BTreeMap::default())
 5972        };
 5973
 5974        let snippets = if let Some(provider) = &provider
 5975            && provider.show_snippets()
 5976            && let Some(project) = self.project()
 5977        {
 5978            let char_classifier = buffer_snapshot
 5979                .char_classifier_at(buffer_position)
 5980                .scope_context(Some(CharScopeContext::Completion));
 5981            project.update(cx, |project, cx| {
 5982                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5983            })
 5984        } else {
 5985            Task::ready(Ok(CompletionResponse {
 5986                completions: Vec::new(),
 5987                display_options: Default::default(),
 5988                is_incomplete: false,
 5989            }))
 5990        };
 5991
 5992        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5993
 5994        let id = post_inc(&mut self.next_completion_id);
 5995        let task = cx.spawn_in(window, async move |editor, cx| {
 5996            let Ok(()) = editor.update(cx, |this, _| {
 5997                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5998            }) else {
 5999                return;
 6000            };
 6001
 6002            // TODO: Ideally completions from different sources would be selectively re-queried, so
 6003            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 6004            let mut completions = Vec::new();
 6005            let mut is_incomplete = false;
 6006            let mut display_options: Option<CompletionDisplayOptions> = None;
 6007            if let Some(provider_responses) = provider_responses.await.log_err()
 6008                && !provider_responses.is_empty()
 6009            {
 6010                for response in provider_responses {
 6011                    completions.extend(response.completions);
 6012                    is_incomplete = is_incomplete || response.is_incomplete;
 6013                    match display_options.as_mut() {
 6014                        None => {
 6015                            display_options = Some(response.display_options);
 6016                        }
 6017                        Some(options) => options.merge(&response.display_options),
 6018                    }
 6019                }
 6020                if completion_settings.words == WordsCompletionMode::Fallback {
 6021                    words = Task::ready(BTreeMap::default());
 6022                }
 6023            }
 6024            let display_options = display_options.unwrap_or_default();
 6025
 6026            let mut words = words.await;
 6027            if let Some(word_to_exclude) = &word_to_exclude {
 6028                words.remove(word_to_exclude);
 6029            }
 6030            for lsp_completion in &completions {
 6031                words.remove(&lsp_completion.new_text);
 6032            }
 6033            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 6034                replace_range: word_replace_range.clone(),
 6035                new_text: word.clone(),
 6036                label: CodeLabel::plain(word, None),
 6037                match_start: None,
 6038                snippet_deduplication_key: None,
 6039                icon_path: None,
 6040                documentation: None,
 6041                source: CompletionSource::BufferWord {
 6042                    word_range,
 6043                    resolved: false,
 6044                },
 6045                insert_text_mode: Some(InsertTextMode::AS_IS),
 6046                confirm: None,
 6047            }));
 6048
 6049            completions.extend(
 6050                snippets
 6051                    .await
 6052                    .into_iter()
 6053                    .flat_map(|response| response.completions),
 6054            );
 6055
 6056            let menu = if completions.is_empty() {
 6057                None
 6058            } else {
 6059                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 6060                    let languages = editor
 6061                        .workspace
 6062                        .as_ref()
 6063                        .and_then(|(workspace, _)| workspace.upgrade())
 6064                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 6065                    let menu = CompletionsMenu::new(
 6066                        id,
 6067                        requested_source.unwrap_or(if load_provider_completions {
 6068                            CompletionsMenuSource::Normal
 6069                        } else {
 6070                            CompletionsMenuSource::SnippetsOnly
 6071                        }),
 6072                        sort_completions,
 6073                        show_completion_documentation,
 6074                        position,
 6075                        query.clone(),
 6076                        is_incomplete,
 6077                        buffer.clone(),
 6078                        completions.into(),
 6079                        editor
 6080                            .context_menu()
 6081                            .borrow_mut()
 6082                            .as_ref()
 6083                            .map(|menu| menu.primary_scroll_handle()),
 6084                        display_options,
 6085                        snippet_sort_order,
 6086                        languages,
 6087                        language,
 6088                        cx,
 6089                    );
 6090
 6091                    let query = if filter_completions { query } else { None };
 6092                    let matches_task = menu.do_async_filtering(
 6093                        query.unwrap_or_default(),
 6094                        buffer_position,
 6095                        &buffer,
 6096                        cx,
 6097                    );
 6098                    (menu, matches_task)
 6099                }) else {
 6100                    return;
 6101                };
 6102
 6103                let matches = matches_task.await;
 6104
 6105                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 6106                    // Newer menu already set, so exit.
 6107                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6108                        editor.context_menu.borrow().as_ref()
 6109                        && prev_menu.id > id
 6110                    {
 6111                        return;
 6112                    };
 6113
 6114                    // Only valid to take prev_menu because either the new menu is immediately set
 6115                    // below, or the menu is hidden.
 6116                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6117                        editor.context_menu.borrow_mut().take()
 6118                    {
 6119                        let position_matches =
 6120                            if prev_menu.initial_position == menu.initial_position {
 6121                                true
 6122                            } else {
 6123                                let snapshot = editor.buffer.read(cx).read(cx);
 6124                                prev_menu.initial_position.to_offset(&snapshot)
 6125                                    == menu.initial_position.to_offset(&snapshot)
 6126                            };
 6127                        if position_matches {
 6128                            // Preserve markdown cache before `set_filter_results` because it will
 6129                            // try to populate the documentation cache.
 6130                            menu.preserve_markdown_cache(prev_menu);
 6131                        }
 6132                    };
 6133
 6134                    menu.set_filter_results(matches, provider, window, cx);
 6135                }) else {
 6136                    return;
 6137                };
 6138
 6139                menu.visible().then_some(menu)
 6140            };
 6141
 6142            editor
 6143                .update_in(cx, |editor, window, cx| {
 6144                    if editor.focus_handle.is_focused(window)
 6145                        && let Some(menu) = menu
 6146                    {
 6147                        *editor.context_menu.borrow_mut() =
 6148                            Some(CodeContextMenu::Completions(menu));
 6149
 6150                        crate::hover_popover::hide_hover(editor, cx);
 6151                        if editor.show_edit_predictions_in_menu() {
 6152                            editor.update_visible_edit_prediction(window, cx);
 6153                        } else {
 6154                            editor.discard_edit_prediction(false, cx);
 6155                        }
 6156
 6157                        cx.notify();
 6158                        return;
 6159                    }
 6160
 6161                    if editor.completion_tasks.len() <= 1 {
 6162                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6163                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6164                        // If it was already hidden and we don't show edit predictions in the menu,
 6165                        // we should also show the edit prediction when available.
 6166                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6167                            editor.update_visible_edit_prediction(window, cx);
 6168                        }
 6169                    }
 6170                })
 6171                .ok();
 6172        });
 6173
 6174        self.completion_tasks.push((id, task));
 6175    }
 6176
 6177    #[cfg(feature = "test-support")]
 6178    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6179        let menu = self.context_menu.borrow();
 6180        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6181            let completions = menu.completions.borrow();
 6182            Some(completions.to_vec())
 6183        } else {
 6184            None
 6185        }
 6186    }
 6187
 6188    pub fn with_completions_menu_matching_id<R>(
 6189        &self,
 6190        id: CompletionId,
 6191        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6192    ) -> R {
 6193        let mut context_menu = self.context_menu.borrow_mut();
 6194        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6195            return f(None);
 6196        };
 6197        if completions_menu.id != id {
 6198            return f(None);
 6199        }
 6200        f(Some(completions_menu))
 6201    }
 6202
 6203    pub fn confirm_completion(
 6204        &mut self,
 6205        action: &ConfirmCompletion,
 6206        window: &mut Window,
 6207        cx: &mut Context<Self>,
 6208    ) -> Option<Task<Result<()>>> {
 6209        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6210        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6211    }
 6212
 6213    pub fn confirm_completion_insert(
 6214        &mut self,
 6215        _: &ConfirmCompletionInsert,
 6216        window: &mut Window,
 6217        cx: &mut Context<Self>,
 6218    ) -> Option<Task<Result<()>>> {
 6219        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6220        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6221    }
 6222
 6223    pub fn confirm_completion_replace(
 6224        &mut self,
 6225        _: &ConfirmCompletionReplace,
 6226        window: &mut Window,
 6227        cx: &mut Context<Self>,
 6228    ) -> Option<Task<Result<()>>> {
 6229        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6230        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6231    }
 6232
 6233    pub fn compose_completion(
 6234        &mut self,
 6235        action: &ComposeCompletion,
 6236        window: &mut Window,
 6237        cx: &mut Context<Self>,
 6238    ) -> Option<Task<Result<()>>> {
 6239        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6240        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6241    }
 6242
 6243    fn do_completion(
 6244        &mut self,
 6245        item_ix: Option<usize>,
 6246        intent: CompletionIntent,
 6247        window: &mut Window,
 6248        cx: &mut Context<Editor>,
 6249    ) -> Option<Task<Result<()>>> {
 6250        use language::ToOffset as _;
 6251
 6252        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6253        else {
 6254            return None;
 6255        };
 6256
 6257        let candidate_id = {
 6258            let entries = completions_menu.entries.borrow();
 6259            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6260            if self.show_edit_predictions_in_menu() {
 6261                self.discard_edit_prediction(true, cx);
 6262            }
 6263            mat.candidate_id
 6264        };
 6265
 6266        let completion = completions_menu
 6267            .completions
 6268            .borrow()
 6269            .get(candidate_id)?
 6270            .clone();
 6271        cx.stop_propagation();
 6272
 6273        let buffer_handle = completions_menu.buffer.clone();
 6274
 6275        let CompletionEdit {
 6276            new_text,
 6277            snippet,
 6278            replace_range,
 6279        } = process_completion_for_edit(
 6280            &completion,
 6281            intent,
 6282            &buffer_handle,
 6283            &completions_menu.initial_position.text_anchor,
 6284            cx,
 6285        );
 6286
 6287        let buffer = buffer_handle.read(cx);
 6288        let snapshot = self.buffer.read(cx).snapshot(cx);
 6289        let newest_anchor = self.selections.newest_anchor();
 6290        let replace_range_multibuffer = {
 6291            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6292            excerpt.map_range_from_buffer(replace_range.clone())
 6293        };
 6294        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6295            return None;
 6296        }
 6297
 6298        let old_text = buffer
 6299            .text_for_range(replace_range.clone())
 6300            .collect::<String>();
 6301        let lookbehind = newest_anchor
 6302            .start
 6303            .text_anchor
 6304            .to_offset(buffer)
 6305            .saturating_sub(replace_range.start.0);
 6306        let lookahead = replace_range
 6307            .end
 6308            .0
 6309            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6310        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6311        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6312
 6313        let selections = self
 6314            .selections
 6315            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6316        let mut ranges = Vec::new();
 6317        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6318
 6319        for selection in &selections {
 6320            let range = if selection.id == newest_anchor.id {
 6321                replace_range_multibuffer.clone()
 6322            } else {
 6323                let mut range = selection.range();
 6324
 6325                // if prefix is present, don't duplicate it
 6326                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6327                    range.start = range.start.saturating_sub_usize(lookbehind);
 6328
 6329                    // if suffix is also present, mimic the newest cursor and replace it
 6330                    if selection.id != newest_anchor.id
 6331                        && snapshot.contains_str_at(range.end, suffix)
 6332                    {
 6333                        range.end += lookahead;
 6334                    }
 6335                }
 6336                range
 6337            };
 6338
 6339            ranges.push(range.clone());
 6340
 6341            if !self.linked_edit_ranges.is_empty() {
 6342                let start_anchor = snapshot.anchor_before(range.start);
 6343                let end_anchor = snapshot.anchor_after(range.end);
 6344                if let Some(ranges) = self
 6345                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6346                {
 6347                    for (buffer, edits) in ranges {
 6348                        linked_edits
 6349                            .entry(buffer.clone())
 6350                            .or_default()
 6351                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6352                    }
 6353                }
 6354            }
 6355        }
 6356
 6357        let common_prefix_len = old_text
 6358            .chars()
 6359            .zip(new_text.chars())
 6360            .take_while(|(a, b)| a == b)
 6361            .map(|(a, _)| a.len_utf8())
 6362            .sum::<usize>();
 6363
 6364        cx.emit(EditorEvent::InputHandled {
 6365            utf16_range_to_replace: None,
 6366            text: new_text[common_prefix_len..].into(),
 6367        });
 6368
 6369        self.transact(window, cx, |editor, window, cx| {
 6370            if let Some(mut snippet) = snippet {
 6371                snippet.text = new_text.to_string();
 6372                editor
 6373                    .insert_snippet(&ranges, snippet, window, cx)
 6374                    .log_err();
 6375            } else {
 6376                editor.buffer.update(cx, |multi_buffer, cx| {
 6377                    let auto_indent = match completion.insert_text_mode {
 6378                        Some(InsertTextMode::AS_IS) => None,
 6379                        _ => editor.autoindent_mode.clone(),
 6380                    };
 6381                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6382                    multi_buffer.edit(edits, auto_indent, cx);
 6383                });
 6384            }
 6385            for (buffer, edits) in linked_edits {
 6386                buffer.update(cx, |buffer, cx| {
 6387                    let snapshot = buffer.snapshot();
 6388                    let edits = edits
 6389                        .into_iter()
 6390                        .map(|(range, text)| {
 6391                            use text::ToPoint as TP;
 6392                            let end_point = TP::to_point(&range.end, &snapshot);
 6393                            let start_point = TP::to_point(&range.start, &snapshot);
 6394                            (start_point..end_point, text)
 6395                        })
 6396                        .sorted_by_key(|(range, _)| range.start);
 6397                    buffer.edit(edits, None, cx);
 6398                })
 6399            }
 6400
 6401            editor.refresh_edit_prediction(true, false, window, cx);
 6402        });
 6403        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6404
 6405        let show_new_completions_on_confirm = completion
 6406            .confirm
 6407            .as_ref()
 6408            .is_some_and(|confirm| confirm(intent, window, cx));
 6409        if show_new_completions_on_confirm {
 6410            self.open_or_update_completions_menu(None, None, false, window, cx);
 6411        }
 6412
 6413        let provider = self.completion_provider.as_ref()?;
 6414
 6415        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6416        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6417            let CompletionSource::Lsp {
 6418                lsp_completion,
 6419                server_id,
 6420                ..
 6421            } = &completion.source
 6422            else {
 6423                return None;
 6424            };
 6425            let lsp_command = lsp_completion.command.as_ref()?;
 6426            let available_commands = lsp_store
 6427                .read(cx)
 6428                .lsp_server_capabilities
 6429                .get(server_id)
 6430                .and_then(|server_capabilities| {
 6431                    server_capabilities
 6432                        .execute_command_provider
 6433                        .as_ref()
 6434                        .map(|options| options.commands.as_slice())
 6435                })?;
 6436            if available_commands.contains(&lsp_command.command) {
 6437                Some(CodeAction {
 6438                    server_id: *server_id,
 6439                    range: language::Anchor::MIN..language::Anchor::MIN,
 6440                    lsp_action: LspAction::Command(lsp_command.clone()),
 6441                    resolved: false,
 6442                })
 6443            } else {
 6444                None
 6445            }
 6446        });
 6447
 6448        drop(completion);
 6449        let apply_edits = provider.apply_additional_edits_for_completion(
 6450            buffer_handle.clone(),
 6451            completions_menu.completions.clone(),
 6452            candidate_id,
 6453            true,
 6454            cx,
 6455        );
 6456
 6457        let editor_settings = EditorSettings::get_global(cx);
 6458        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6459            // After the code completion is finished, users often want to know what signatures are needed.
 6460            // so we should automatically call signature_help
 6461            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6462        }
 6463
 6464        Some(cx.spawn_in(window, async move |editor, cx| {
 6465            apply_edits.await?;
 6466
 6467            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6468                let title = command.lsp_action.title().to_owned();
 6469                let project_transaction = lsp_store
 6470                    .update(cx, |lsp_store, cx| {
 6471                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6472                    })
 6473                    .await
 6474                    .context("applying post-completion command")?;
 6475                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6476                    Self::open_project_transaction(
 6477                        &editor,
 6478                        workspace.downgrade(),
 6479                        project_transaction,
 6480                        title,
 6481                        cx,
 6482                    )
 6483                    .await?;
 6484                }
 6485            }
 6486
 6487            Ok(())
 6488        }))
 6489    }
 6490
 6491    pub fn toggle_code_actions(
 6492        &mut self,
 6493        action: &ToggleCodeActions,
 6494        window: &mut Window,
 6495        cx: &mut Context<Self>,
 6496    ) {
 6497        let quick_launch = action.quick_launch;
 6498        let mut context_menu = self.context_menu.borrow_mut();
 6499        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6500            if code_actions.deployed_from == action.deployed_from {
 6501                // Toggle if we're selecting the same one
 6502                *context_menu = None;
 6503                cx.notify();
 6504                return;
 6505            } else {
 6506                // Otherwise, clear it and start a new one
 6507                *context_menu = None;
 6508                cx.notify();
 6509            }
 6510        }
 6511        drop(context_menu);
 6512        let snapshot = self.snapshot(window, cx);
 6513        let deployed_from = action.deployed_from.clone();
 6514        let action = action.clone();
 6515        self.completion_tasks.clear();
 6516        self.discard_edit_prediction(false, cx);
 6517
 6518        let multibuffer_point = match &action.deployed_from {
 6519            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6520                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6521            }
 6522            _ => self
 6523                .selections
 6524                .newest::<Point>(&snapshot.display_snapshot)
 6525                .head(),
 6526        };
 6527        let Some((buffer, buffer_row)) = snapshot
 6528            .buffer_snapshot()
 6529            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6530            .and_then(|(buffer_snapshot, range)| {
 6531                self.buffer()
 6532                    .read(cx)
 6533                    .buffer(buffer_snapshot.remote_id())
 6534                    .map(|buffer| (buffer, range.start.row))
 6535            })
 6536        else {
 6537            return;
 6538        };
 6539        let buffer_id = buffer.read(cx).remote_id();
 6540        let tasks = self
 6541            .tasks
 6542            .get(&(buffer_id, buffer_row))
 6543            .map(|t| Arc::new(t.to_owned()));
 6544
 6545        if !self.focus_handle.is_focused(window) {
 6546            return;
 6547        }
 6548        let project = self.project.clone();
 6549
 6550        let code_actions_task = match deployed_from {
 6551            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6552            _ => self.code_actions(buffer_row, window, cx),
 6553        };
 6554
 6555        let runnable_task = match deployed_from {
 6556            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6557            _ => {
 6558                let mut task_context_task = Task::ready(None);
 6559                if let Some(tasks) = &tasks
 6560                    && let Some(project) = project
 6561                {
 6562                    task_context_task =
 6563                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6564                }
 6565
 6566                cx.spawn_in(window, {
 6567                    let buffer = buffer.clone();
 6568                    async move |editor, cx| {
 6569                        let task_context = task_context_task.await;
 6570
 6571                        let resolved_tasks =
 6572                            tasks
 6573                                .zip(task_context.clone())
 6574                                .map(|(tasks, task_context)| ResolvedTasks {
 6575                                    templates: tasks.resolve(&task_context).collect(),
 6576                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6577                                        multibuffer_point.row,
 6578                                        tasks.column,
 6579                                    )),
 6580                                });
 6581                        let debug_scenarios = editor
 6582                            .update(cx, |editor, cx| {
 6583                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6584                            })?
 6585                            .await;
 6586                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6587                    }
 6588                })
 6589            }
 6590        };
 6591
 6592        cx.spawn_in(window, async move |editor, cx| {
 6593            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6594            let code_actions = code_actions_task.await;
 6595            let spawn_straight_away = quick_launch
 6596                && resolved_tasks
 6597                    .as_ref()
 6598                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6599                && code_actions
 6600                    .as_ref()
 6601                    .is_none_or(|actions| actions.is_empty())
 6602                && debug_scenarios.is_empty();
 6603
 6604            editor.update_in(cx, |editor, window, cx| {
 6605                crate::hover_popover::hide_hover(editor, cx);
 6606                let actions = CodeActionContents::new(
 6607                    resolved_tasks,
 6608                    code_actions,
 6609                    debug_scenarios,
 6610                    task_context.unwrap_or_default(),
 6611                );
 6612
 6613                // Don't show the menu if there are no actions available
 6614                if actions.is_empty() {
 6615                    cx.notify();
 6616                    return Task::ready(Ok(()));
 6617                }
 6618
 6619                *editor.context_menu.borrow_mut() =
 6620                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6621                        buffer,
 6622                        actions,
 6623                        selected_item: Default::default(),
 6624                        scroll_handle: UniformListScrollHandle::default(),
 6625                        deployed_from,
 6626                    }));
 6627                cx.notify();
 6628                if spawn_straight_away
 6629                    && let Some(task) = editor.confirm_code_action(
 6630                        &ConfirmCodeAction { item_ix: Some(0) },
 6631                        window,
 6632                        cx,
 6633                    )
 6634                {
 6635                    return task;
 6636                }
 6637
 6638                Task::ready(Ok(()))
 6639            })
 6640        })
 6641        .detach_and_log_err(cx);
 6642    }
 6643
 6644    fn debug_scenarios(
 6645        &mut self,
 6646        resolved_tasks: &Option<ResolvedTasks>,
 6647        buffer: &Entity<Buffer>,
 6648        cx: &mut App,
 6649    ) -> Task<Vec<task::DebugScenario>> {
 6650        maybe!({
 6651            let project = self.project()?;
 6652            let dap_store = project.read(cx).dap_store();
 6653            let mut scenarios = vec![];
 6654            let resolved_tasks = resolved_tasks.as_ref()?;
 6655            let buffer = buffer.read(cx);
 6656            let language = buffer.language()?;
 6657            let file = buffer.file();
 6658            let debug_adapter = language_settings(language.name().into(), file, cx)
 6659                .debuggers
 6660                .first()
 6661                .map(SharedString::from)
 6662                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6663
 6664            dap_store.update(cx, |dap_store, cx| {
 6665                for (_, task) in &resolved_tasks.templates {
 6666                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6667                        task.original_task().clone(),
 6668                        debug_adapter.clone().into(),
 6669                        task.display_label().to_owned().into(),
 6670                        cx,
 6671                    );
 6672                    scenarios.push(maybe_scenario);
 6673                }
 6674            });
 6675            Some(cx.background_spawn(async move {
 6676                futures::future::join_all(scenarios)
 6677                    .await
 6678                    .into_iter()
 6679                    .flatten()
 6680                    .collect::<Vec<_>>()
 6681            }))
 6682        })
 6683        .unwrap_or_else(|| Task::ready(vec![]))
 6684    }
 6685
 6686    fn code_actions(
 6687        &mut self,
 6688        buffer_row: u32,
 6689        window: &mut Window,
 6690        cx: &mut Context<Self>,
 6691    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6692        let mut task = self.code_actions_task.take();
 6693        cx.spawn_in(window, async move |editor, cx| {
 6694            while let Some(prev_task) = task {
 6695                prev_task.await.log_err();
 6696                task = editor
 6697                    .update(cx, |this, _| this.code_actions_task.take())
 6698                    .ok()?;
 6699            }
 6700
 6701            editor
 6702                .update(cx, |editor, cx| {
 6703                    editor
 6704                        .available_code_actions
 6705                        .clone()
 6706                        .and_then(|(location, code_actions)| {
 6707                            let snapshot = location.buffer.read(cx).snapshot();
 6708                            let point_range = location.range.to_point(&snapshot);
 6709                            let point_range = point_range.start.row..=point_range.end.row;
 6710                            if point_range.contains(&buffer_row) {
 6711                                Some(code_actions)
 6712                            } else {
 6713                                None
 6714                            }
 6715                        })
 6716                })
 6717                .ok()
 6718                .flatten()
 6719        })
 6720    }
 6721
 6722    pub fn confirm_code_action(
 6723        &mut self,
 6724        action: &ConfirmCodeAction,
 6725        window: &mut Window,
 6726        cx: &mut Context<Self>,
 6727    ) -> Option<Task<Result<()>>> {
 6728        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6729
 6730        let actions_menu =
 6731            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6732                menu
 6733            } else {
 6734                return None;
 6735            };
 6736
 6737        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6738        let action = actions_menu.actions.get(action_ix)?;
 6739        let title = action.label();
 6740        let buffer = actions_menu.buffer;
 6741        let workspace = self.workspace()?;
 6742
 6743        match action {
 6744            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6745                workspace.update(cx, |workspace, cx| {
 6746                    workspace.schedule_resolved_task(
 6747                        task_source_kind,
 6748                        resolved_task,
 6749                        false,
 6750                        window,
 6751                        cx,
 6752                    );
 6753
 6754                    Some(Task::ready(Ok(())))
 6755                })
 6756            }
 6757            CodeActionsItem::CodeAction {
 6758                excerpt_id,
 6759                action,
 6760                provider,
 6761            } => {
 6762                let apply_code_action =
 6763                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6764                let workspace = workspace.downgrade();
 6765                Some(cx.spawn_in(window, async move |editor, cx| {
 6766                    let project_transaction = apply_code_action.await?;
 6767                    Self::open_project_transaction(
 6768                        &editor,
 6769                        workspace,
 6770                        project_transaction,
 6771                        title,
 6772                        cx,
 6773                    )
 6774                    .await
 6775                }))
 6776            }
 6777            CodeActionsItem::DebugScenario(scenario) => {
 6778                let context = actions_menu.actions.context;
 6779
 6780                workspace.update(cx, |workspace, cx| {
 6781                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6782                    workspace.start_debug_session(
 6783                        scenario,
 6784                        context,
 6785                        Some(buffer),
 6786                        None,
 6787                        window,
 6788                        cx,
 6789                    );
 6790                });
 6791                Some(Task::ready(Ok(())))
 6792            }
 6793        }
 6794    }
 6795
 6796    fn open_transaction_for_hidden_buffers(
 6797        workspace: Entity<Workspace>,
 6798        transaction: ProjectTransaction,
 6799        title: String,
 6800        window: &mut Window,
 6801        cx: &mut Context<Self>,
 6802    ) {
 6803        if transaction.0.is_empty() {
 6804            return;
 6805        }
 6806
 6807        let edited_buffers_already_open = {
 6808            let other_editors: Vec<Entity<Editor>> = workspace
 6809                .read(cx)
 6810                .panes()
 6811                .iter()
 6812                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6813                .filter(|editor| editor.entity_id() != cx.entity_id())
 6814                .collect();
 6815
 6816            transaction.0.keys().all(|buffer| {
 6817                other_editors.iter().any(|editor| {
 6818                    let multi_buffer = editor.read(cx).buffer();
 6819                    multi_buffer.read(cx).is_singleton()
 6820                        && multi_buffer
 6821                            .read(cx)
 6822                            .as_singleton()
 6823                            .map_or(false, |singleton| {
 6824                                singleton.entity_id() == buffer.entity_id()
 6825                            })
 6826                })
 6827            })
 6828        };
 6829        if !edited_buffers_already_open {
 6830            let workspace = workspace.downgrade();
 6831            cx.defer_in(window, move |_, window, cx| {
 6832                cx.spawn_in(window, async move |editor, cx| {
 6833                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6834                        .await
 6835                        .ok()
 6836                })
 6837                .detach();
 6838            });
 6839        }
 6840    }
 6841
 6842    pub async fn open_project_transaction(
 6843        editor: &WeakEntity<Editor>,
 6844        workspace: WeakEntity<Workspace>,
 6845        transaction: ProjectTransaction,
 6846        title: String,
 6847        cx: &mut AsyncWindowContext,
 6848    ) -> Result<()> {
 6849        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6850        cx.update(|_, cx| {
 6851            entries.sort_unstable_by_key(|(buffer, _)| {
 6852                buffer.read(cx).file().map(|f| f.path().clone())
 6853            });
 6854        })?;
 6855        if entries.is_empty() {
 6856            return Ok(());
 6857        }
 6858
 6859        // If the project transaction's edits are all contained within this editor, then
 6860        // avoid opening a new editor to display them.
 6861
 6862        if let [(buffer, transaction)] = &*entries {
 6863            let excerpt = editor.update(cx, |editor, cx| {
 6864                editor
 6865                    .buffer()
 6866                    .read(cx)
 6867                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6868            })?;
 6869            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6870                && excerpted_buffer == *buffer
 6871            {
 6872                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6873                    let excerpt_range = excerpt_range.to_offset(buffer);
 6874                    buffer
 6875                        .edited_ranges_for_transaction::<usize>(transaction)
 6876                        .all(|range| {
 6877                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6878                        })
 6879                });
 6880
 6881                if all_edits_within_excerpt {
 6882                    return Ok(());
 6883                }
 6884            }
 6885        }
 6886
 6887        let mut ranges_to_highlight = Vec::new();
 6888        let excerpt_buffer = cx.new(|cx| {
 6889            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6890            for (buffer_handle, transaction) in &entries {
 6891                let edited_ranges = buffer_handle
 6892                    .read(cx)
 6893                    .edited_ranges_for_transaction::<Point>(transaction)
 6894                    .collect::<Vec<_>>();
 6895                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6896                    PathKey::for_buffer(buffer_handle, cx),
 6897                    buffer_handle.clone(),
 6898                    edited_ranges,
 6899                    multibuffer_context_lines(cx),
 6900                    cx,
 6901                );
 6902
 6903                ranges_to_highlight.extend(ranges);
 6904            }
 6905            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6906            multibuffer
 6907        });
 6908
 6909        workspace.update_in(cx, |workspace, window, cx| {
 6910            let project = workspace.project().clone();
 6911            let editor =
 6912                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6913            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6914            editor.update(cx, |editor, cx| {
 6915                editor.highlight_background::<Self>(
 6916                    &ranges_to_highlight,
 6917                    |_, theme| theme.colors().editor_highlighted_line_background,
 6918                    cx,
 6919                );
 6920            });
 6921        })?;
 6922
 6923        Ok(())
 6924    }
 6925
 6926    pub fn clear_code_action_providers(&mut self) {
 6927        self.code_action_providers.clear();
 6928        self.available_code_actions.take();
 6929    }
 6930
 6931    pub fn add_code_action_provider(
 6932        &mut self,
 6933        provider: Rc<dyn CodeActionProvider>,
 6934        window: &mut Window,
 6935        cx: &mut Context<Self>,
 6936    ) {
 6937        if self
 6938            .code_action_providers
 6939            .iter()
 6940            .any(|existing_provider| existing_provider.id() == provider.id())
 6941        {
 6942            return;
 6943        }
 6944
 6945        self.code_action_providers.push(provider);
 6946        self.refresh_code_actions(window, cx);
 6947    }
 6948
 6949    pub fn remove_code_action_provider(
 6950        &mut self,
 6951        id: Arc<str>,
 6952        window: &mut Window,
 6953        cx: &mut Context<Self>,
 6954    ) {
 6955        self.code_action_providers
 6956            .retain(|provider| provider.id() != id);
 6957        self.refresh_code_actions(window, cx);
 6958    }
 6959
 6960    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6961        !self.code_action_providers.is_empty()
 6962            && EditorSettings::get_global(cx).toolbar.code_actions
 6963    }
 6964
 6965    pub fn has_available_code_actions(&self) -> bool {
 6966        self.available_code_actions
 6967            .as_ref()
 6968            .is_some_and(|(_, actions)| !actions.is_empty())
 6969    }
 6970
 6971    fn render_inline_code_actions(
 6972        &self,
 6973        icon_size: ui::IconSize,
 6974        display_row: DisplayRow,
 6975        is_active: bool,
 6976        cx: &mut Context<Self>,
 6977    ) -> AnyElement {
 6978        let show_tooltip = !self.context_menu_visible();
 6979        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6980            .icon_size(icon_size)
 6981            .shape(ui::IconButtonShape::Square)
 6982            .icon_color(ui::Color::Hidden)
 6983            .toggle_state(is_active)
 6984            .when(show_tooltip, |this| {
 6985                this.tooltip({
 6986                    let focus_handle = self.focus_handle.clone();
 6987                    move |_window, cx| {
 6988                        Tooltip::for_action_in(
 6989                            "Toggle Code Actions",
 6990                            &ToggleCodeActions {
 6991                                deployed_from: None,
 6992                                quick_launch: false,
 6993                            },
 6994                            &focus_handle,
 6995                            cx,
 6996                        )
 6997                    }
 6998                })
 6999            })
 7000            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 7001                window.focus(&editor.focus_handle(cx), cx);
 7002                editor.toggle_code_actions(
 7003                    &crate::actions::ToggleCodeActions {
 7004                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 7005                            display_row,
 7006                        )),
 7007                        quick_launch: false,
 7008                    },
 7009                    window,
 7010                    cx,
 7011                );
 7012            }))
 7013            .into_any_element()
 7014    }
 7015
 7016    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 7017        &self.context_menu
 7018    }
 7019
 7020    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7021        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 7022            cx.background_executor()
 7023                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 7024                .await;
 7025
 7026            let (start_buffer, start, _, end, newest_selection) = this
 7027                .update(cx, |this, cx| {
 7028                    let newest_selection = this.selections.newest_anchor().clone();
 7029                    if newest_selection.head().diff_base_anchor.is_some() {
 7030                        return None;
 7031                    }
 7032                    let display_snapshot = this.display_snapshot(cx);
 7033                    let newest_selection_adjusted =
 7034                        this.selections.newest_adjusted(&display_snapshot);
 7035                    let buffer = this.buffer.read(cx);
 7036
 7037                    let (start_buffer, start) =
 7038                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 7039                    let (end_buffer, end) =
 7040                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 7041
 7042                    Some((start_buffer, start, end_buffer, end, newest_selection))
 7043                })?
 7044                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 7045                .context(
 7046                    "Expected selection to lie in a single buffer when refreshing code actions",
 7047                )?;
 7048            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 7049                let providers = this.code_action_providers.clone();
 7050                let tasks = this
 7051                    .code_action_providers
 7052                    .iter()
 7053                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 7054                    .collect::<Vec<_>>();
 7055                (providers, tasks)
 7056            })?;
 7057
 7058            let mut actions = Vec::new();
 7059            for (provider, provider_actions) in
 7060                providers.into_iter().zip(future::join_all(tasks).await)
 7061            {
 7062                if let Some(provider_actions) = provider_actions.log_err() {
 7063                    actions.extend(provider_actions.into_iter().map(|action| {
 7064                        AvailableCodeAction {
 7065                            excerpt_id: newest_selection.start.excerpt_id,
 7066                            action,
 7067                            provider: provider.clone(),
 7068                        }
 7069                    }));
 7070                }
 7071            }
 7072
 7073            this.update(cx, |this, cx| {
 7074                this.available_code_actions = if actions.is_empty() {
 7075                    None
 7076                } else {
 7077                    Some((
 7078                        Location {
 7079                            buffer: start_buffer,
 7080                            range: start..end,
 7081                        },
 7082                        actions.into(),
 7083                    ))
 7084                };
 7085                cx.notify();
 7086            })
 7087        }));
 7088    }
 7089
 7090    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7091        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 7092            self.show_git_blame_inline = false;
 7093
 7094            self.show_git_blame_inline_delay_task =
 7095                Some(cx.spawn_in(window, async move |this, cx| {
 7096                    cx.background_executor().timer(delay).await;
 7097
 7098                    this.update(cx, |this, cx| {
 7099                        this.show_git_blame_inline = true;
 7100                        cx.notify();
 7101                    })
 7102                    .log_err();
 7103                }));
 7104        }
 7105    }
 7106
 7107    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 7108        let snapshot = self.snapshot(window, cx);
 7109        let cursor = self
 7110            .selections
 7111            .newest::<Point>(&snapshot.display_snapshot)
 7112            .head();
 7113        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 7114        else {
 7115            return;
 7116        };
 7117
 7118        if self.blame.is_none() {
 7119            self.start_git_blame(true, window, cx);
 7120        }
 7121        let Some(blame) = self.blame.as_ref() else {
 7122            return;
 7123        };
 7124
 7125        let row_info = RowInfo {
 7126            buffer_id: Some(buffer.remote_id()),
 7127            buffer_row: Some(point.row),
 7128            ..Default::default()
 7129        };
 7130        let Some((buffer, blame_entry)) = blame
 7131            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 7132            .flatten()
 7133        else {
 7134            return;
 7135        };
 7136
 7137        let anchor = self.selections.newest_anchor().head();
 7138        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 7139        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 7140            self.show_blame_popover(
 7141                buffer,
 7142                &blame_entry,
 7143                position + last_bounds.origin,
 7144                true,
 7145                cx,
 7146            );
 7147        };
 7148    }
 7149
 7150    fn show_blame_popover(
 7151        &mut self,
 7152        buffer: BufferId,
 7153        blame_entry: &BlameEntry,
 7154        position: gpui::Point<Pixels>,
 7155        ignore_timeout: bool,
 7156        cx: &mut Context<Self>,
 7157    ) {
 7158        if let Some(state) = &mut self.inline_blame_popover {
 7159            state.hide_task.take();
 7160        } else {
 7161            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 7162            let blame_entry = blame_entry.clone();
 7163            let show_task = cx.spawn(async move |editor, cx| {
 7164                if !ignore_timeout {
 7165                    cx.background_executor()
 7166                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7167                        .await;
 7168                }
 7169                editor
 7170                    .update(cx, |editor, cx| {
 7171                        editor.inline_blame_popover_show_task.take();
 7172                        let Some(blame) = editor.blame.as_ref() else {
 7173                            return;
 7174                        };
 7175                        let blame = blame.read(cx);
 7176                        let details = blame.details_for_entry(buffer, &blame_entry);
 7177                        let markdown = cx.new(|cx| {
 7178                            Markdown::new(
 7179                                details
 7180                                    .as_ref()
 7181                                    .map(|message| message.message.clone())
 7182                                    .unwrap_or_default(),
 7183                                None,
 7184                                None,
 7185                                cx,
 7186                            )
 7187                        });
 7188                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7189                            position,
 7190                            hide_task: None,
 7191                            popover_bounds: None,
 7192                            popover_state: InlineBlamePopoverState {
 7193                                scroll_handle: ScrollHandle::new(),
 7194                                commit_message: details,
 7195                                markdown,
 7196                            },
 7197                            keyboard_grace: ignore_timeout,
 7198                        });
 7199                        cx.notify();
 7200                    })
 7201                    .ok();
 7202            });
 7203            self.inline_blame_popover_show_task = Some(show_task);
 7204        }
 7205    }
 7206
 7207    pub fn has_mouse_context_menu(&self) -> bool {
 7208        self.mouse_context_menu.is_some()
 7209    }
 7210
 7211    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7212        self.inline_blame_popover_show_task.take();
 7213        if let Some(state) = &mut self.inline_blame_popover {
 7214            let hide_task = cx.spawn(async move |editor, cx| {
 7215                if !ignore_timeout {
 7216                    cx.background_executor()
 7217                        .timer(std::time::Duration::from_millis(100))
 7218                        .await;
 7219                }
 7220                editor
 7221                    .update(cx, |editor, cx| {
 7222                        editor.inline_blame_popover.take();
 7223                        cx.notify();
 7224                    })
 7225                    .ok();
 7226            });
 7227            state.hide_task = Some(hide_task);
 7228            true
 7229        } else {
 7230            false
 7231        }
 7232    }
 7233
 7234    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7235        if self.pending_rename.is_some() {
 7236            return None;
 7237        }
 7238
 7239        let provider = self.semantics_provider.clone()?;
 7240        let buffer = self.buffer.read(cx);
 7241        let newest_selection = self.selections.newest_anchor().clone();
 7242        let cursor_position = newest_selection.head();
 7243        let (cursor_buffer, cursor_buffer_position) =
 7244            buffer.text_anchor_for_position(cursor_position, cx)?;
 7245        let (tail_buffer, tail_buffer_position) =
 7246            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7247        if cursor_buffer != tail_buffer {
 7248            return None;
 7249        }
 7250
 7251        let snapshot = cursor_buffer.read(cx).snapshot();
 7252        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7253        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7254        if start_word_range != end_word_range {
 7255            self.document_highlights_task.take();
 7256            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7257            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7258            return None;
 7259        }
 7260
 7261        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7262        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7263            cx.background_executor()
 7264                .timer(Duration::from_millis(debounce))
 7265                .await;
 7266
 7267            let highlights = if let Some(highlights) = cx.update(|cx| {
 7268                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7269            }) {
 7270                highlights.await.log_err()
 7271            } else {
 7272                None
 7273            };
 7274
 7275            if let Some(highlights) = highlights {
 7276                this.update(cx, |this, cx| {
 7277                    if this.pending_rename.is_some() {
 7278                        return;
 7279                    }
 7280
 7281                    let buffer = this.buffer.read(cx);
 7282                    if buffer
 7283                        .text_anchor_for_position(cursor_position, cx)
 7284                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7285                    {
 7286                        return;
 7287                    }
 7288
 7289                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7290                    let mut write_ranges = Vec::new();
 7291                    let mut read_ranges = Vec::new();
 7292                    for highlight in highlights {
 7293                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7294                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7295                        {
 7296                            let start = highlight
 7297                                .range
 7298                                .start
 7299                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7300                            let end = highlight
 7301                                .range
 7302                                .end
 7303                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7304                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7305                                continue;
 7306                            }
 7307
 7308                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7309                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7310                                write_ranges.push(range);
 7311                            } else {
 7312                                read_ranges.push(range);
 7313                            }
 7314                        }
 7315                    }
 7316
 7317                    this.highlight_background::<DocumentHighlightRead>(
 7318                        &read_ranges,
 7319                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7320                        cx,
 7321                    );
 7322                    this.highlight_background::<DocumentHighlightWrite>(
 7323                        &write_ranges,
 7324                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7325                        cx,
 7326                    );
 7327                    cx.notify();
 7328                })
 7329                .log_err();
 7330            }
 7331        }));
 7332        None
 7333    }
 7334
 7335    fn prepare_highlight_query_from_selection(
 7336        &mut self,
 7337        window: &Window,
 7338        cx: &mut Context<Editor>,
 7339    ) -> Option<(String, Range<Anchor>)> {
 7340        if matches!(self.mode, EditorMode::SingleLine) {
 7341            return None;
 7342        }
 7343        if !EditorSettings::get_global(cx).selection_highlight {
 7344            return None;
 7345        }
 7346        if self.selections.count() != 1 || self.selections.line_mode() {
 7347            return None;
 7348        }
 7349        let snapshot = self.snapshot(window, cx);
 7350        let selection = self.selections.newest::<Point>(&snapshot);
 7351        // If the selection spans multiple rows OR it is empty
 7352        if selection.start.row != selection.end.row
 7353            || selection.start.column == selection.end.column
 7354        {
 7355            return None;
 7356        }
 7357        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7358        let query = snapshot
 7359            .buffer_snapshot()
 7360            .text_for_range(selection_anchor_range.clone())
 7361            .collect::<String>();
 7362        if query.trim().is_empty() {
 7363            return None;
 7364        }
 7365        Some((query, selection_anchor_range))
 7366    }
 7367
 7368    #[ztracing::instrument(skip_all)]
 7369    fn update_selection_occurrence_highlights(
 7370        &mut self,
 7371        query_text: String,
 7372        query_range: Range<Anchor>,
 7373        multi_buffer_range_to_query: Range<Point>,
 7374        use_debounce: bool,
 7375        window: &mut Window,
 7376        cx: &mut Context<Editor>,
 7377    ) -> Task<()> {
 7378        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7379        cx.spawn_in(window, async move |editor, cx| {
 7380            if use_debounce {
 7381                cx.background_executor()
 7382                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7383                    .await;
 7384            }
 7385            let match_task = cx.background_spawn(async move {
 7386                let buffer_ranges = multi_buffer_snapshot
 7387                    .range_to_buffer_ranges(
 7388                        multi_buffer_range_to_query.start..=multi_buffer_range_to_query.end,
 7389                    )
 7390                    .into_iter()
 7391                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7392                let mut match_ranges = Vec::new();
 7393                let Ok(regex) = project::search::SearchQuery::text(
 7394                    query_text.clone(),
 7395                    false,
 7396                    false,
 7397                    false,
 7398                    Default::default(),
 7399                    Default::default(),
 7400                    false,
 7401                    None,
 7402                ) else {
 7403                    return Vec::default();
 7404                };
 7405                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7406                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7407                    match_ranges.extend(
 7408                        regex
 7409                            .search(
 7410                                buffer_snapshot,
 7411                                Some(search_range.start.0..search_range.end.0),
 7412                            )
 7413                            .await
 7414                            .into_iter()
 7415                            .filter_map(|match_range| {
 7416                                let match_start = buffer_snapshot
 7417                                    .anchor_after(search_range.start + match_range.start);
 7418                                let match_end = buffer_snapshot
 7419                                    .anchor_before(search_range.start + match_range.end);
 7420                                let match_anchor_range =
 7421                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7422                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7423                            }),
 7424                    );
 7425                }
 7426                match_ranges
 7427            });
 7428            let match_ranges = match_task.await;
 7429            editor
 7430                .update_in(cx, |editor, _, cx| {
 7431                    if use_debounce {
 7432                        editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7433                        editor.debounced_selection_highlight_complete = true;
 7434                    } else if editor.debounced_selection_highlight_complete {
 7435                        return;
 7436                    }
 7437                    if !match_ranges.is_empty() {
 7438                        editor.highlight_background::<SelectedTextHighlight>(
 7439                            &match_ranges,
 7440                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7441                            cx,
 7442                        )
 7443                    }
 7444                })
 7445                .log_err();
 7446        })
 7447    }
 7448
 7449    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7450        struct NewlineFold;
 7451        let type_id = std::any::TypeId::of::<NewlineFold>();
 7452        if !self.mode.is_single_line() {
 7453            return;
 7454        }
 7455        let snapshot = self.snapshot(window, cx);
 7456        if snapshot.buffer_snapshot().max_point().row == 0 {
 7457            return;
 7458        }
 7459        let task = cx.background_spawn(async move {
 7460            let new_newlines = snapshot
 7461                .buffer_chars_at(MultiBufferOffset(0))
 7462                .filter_map(|(c, i)| {
 7463                    if c == '\n' {
 7464                        Some(
 7465                            snapshot.buffer_snapshot().anchor_after(i)
 7466                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7467                        )
 7468                    } else {
 7469                        None
 7470                    }
 7471                })
 7472                .collect::<Vec<_>>();
 7473            let existing_newlines = snapshot
 7474                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7475                .filter_map(|fold| {
 7476                    if fold.placeholder.type_tag == Some(type_id) {
 7477                        Some(fold.range.start..fold.range.end)
 7478                    } else {
 7479                        None
 7480                    }
 7481                })
 7482                .collect::<Vec<_>>();
 7483
 7484            (new_newlines, existing_newlines)
 7485        });
 7486        self.folding_newlines = cx.spawn(async move |this, cx| {
 7487            let (new_newlines, existing_newlines) = task.await;
 7488            if new_newlines == existing_newlines {
 7489                return;
 7490            }
 7491            let placeholder = FoldPlaceholder {
 7492                render: Arc::new(move |_, _, cx| {
 7493                    div()
 7494                        .bg(cx.theme().status().hint_background)
 7495                        .border_b_1()
 7496                        .size_full()
 7497                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7498                        .border_color(cx.theme().status().hint)
 7499                        .child("\\n")
 7500                        .into_any()
 7501                }),
 7502                constrain_width: false,
 7503                merge_adjacent: false,
 7504                type_tag: Some(type_id),
 7505            };
 7506            let creases = new_newlines
 7507                .into_iter()
 7508                .map(|range| Crease::simple(range, placeholder.clone()))
 7509                .collect();
 7510            this.update(cx, |this, cx| {
 7511                this.display_map.update(cx, |display_map, cx| {
 7512                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7513                    display_map.fold(creases, cx);
 7514                });
 7515            })
 7516            .ok();
 7517        });
 7518    }
 7519
 7520    #[ztracing::instrument(skip_all)]
 7521    fn refresh_selected_text_highlights(
 7522        &mut self,
 7523        on_buffer_edit: bool,
 7524        window: &mut Window,
 7525        cx: &mut Context<Editor>,
 7526    ) {
 7527        let Some((query_text, query_range)) =
 7528            self.prepare_highlight_query_from_selection(window, cx)
 7529        else {
 7530            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7531            self.quick_selection_highlight_task.take();
 7532            self.debounced_selection_highlight_task.take();
 7533            self.debounced_selection_highlight_complete = false;
 7534            return;
 7535        };
 7536        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7537        let query_changed = self
 7538            .quick_selection_highlight_task
 7539            .as_ref()
 7540            .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range);
 7541        if query_changed {
 7542            self.debounced_selection_highlight_complete = false;
 7543        }
 7544        if on_buffer_edit || query_changed {
 7545            let multi_buffer_visible_start = self
 7546                .scroll_manager
 7547                .anchor()
 7548                .anchor
 7549                .to_point(&multi_buffer_snapshot);
 7550            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7551                multi_buffer_visible_start
 7552                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7553                Bias::Left,
 7554            );
 7555            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7556            self.quick_selection_highlight_task = Some((
 7557                query_range.clone(),
 7558                self.update_selection_occurrence_highlights(
 7559                    query_text.clone(),
 7560                    query_range.clone(),
 7561                    multi_buffer_visible_range,
 7562                    false,
 7563                    window,
 7564                    cx,
 7565                ),
 7566            ));
 7567        }
 7568        if on_buffer_edit
 7569            || self
 7570                .debounced_selection_highlight_task
 7571                .as_ref()
 7572                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7573        {
 7574            let multi_buffer_start = multi_buffer_snapshot
 7575                .anchor_before(MultiBufferOffset(0))
 7576                .to_point(&multi_buffer_snapshot);
 7577            let multi_buffer_end = multi_buffer_snapshot
 7578                .anchor_after(multi_buffer_snapshot.len())
 7579                .to_point(&multi_buffer_snapshot);
 7580            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7581            self.debounced_selection_highlight_task = Some((
 7582                query_range.clone(),
 7583                self.update_selection_occurrence_highlights(
 7584                    query_text,
 7585                    query_range,
 7586                    multi_buffer_full_range,
 7587                    true,
 7588                    window,
 7589                    cx,
 7590                ),
 7591            ));
 7592        }
 7593    }
 7594
 7595    pub fn refresh_edit_prediction(
 7596        &mut self,
 7597        debounce: bool,
 7598        user_requested: bool,
 7599        window: &mut Window,
 7600        cx: &mut Context<Self>,
 7601    ) -> Option<()> {
 7602        if DisableAiSettings::get_global(cx).disable_ai {
 7603            return None;
 7604        }
 7605
 7606        let provider = self.edit_prediction_provider()?;
 7607        let cursor = self.selections.newest_anchor().head();
 7608        let (buffer, cursor_buffer_position) =
 7609            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7610
 7611        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7612            self.discard_edit_prediction(false, cx);
 7613            return None;
 7614        }
 7615
 7616        self.update_visible_edit_prediction(window, cx);
 7617
 7618        if !user_requested
 7619            && (!self.should_show_edit_predictions()
 7620                || !self.is_focused(window)
 7621                || buffer.read(cx).is_empty())
 7622        {
 7623            self.discard_edit_prediction(false, cx);
 7624            return None;
 7625        }
 7626
 7627        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7628        Some(())
 7629    }
 7630
 7631    fn show_edit_predictions_in_menu(&self) -> bool {
 7632        match self.edit_prediction_settings {
 7633            EditPredictionSettings::Disabled => false,
 7634            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7635        }
 7636    }
 7637
 7638    pub fn edit_predictions_enabled(&self) -> bool {
 7639        match self.edit_prediction_settings {
 7640            EditPredictionSettings::Disabled => false,
 7641            EditPredictionSettings::Enabled { .. } => true,
 7642        }
 7643    }
 7644
 7645    fn edit_prediction_requires_modifier(&self) -> bool {
 7646        match self.edit_prediction_settings {
 7647            EditPredictionSettings::Disabled => false,
 7648            EditPredictionSettings::Enabled {
 7649                preview_requires_modifier,
 7650                ..
 7651            } => preview_requires_modifier,
 7652        }
 7653    }
 7654
 7655    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7656        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7657            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7658            self.discard_edit_prediction(false, cx);
 7659        } else {
 7660            let selection = self.selections.newest_anchor();
 7661            let cursor = selection.head();
 7662
 7663            if let Some((buffer, cursor_buffer_position)) =
 7664                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7665            {
 7666                self.edit_prediction_settings =
 7667                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7668            }
 7669        }
 7670    }
 7671
 7672    fn edit_prediction_settings_at_position(
 7673        &self,
 7674        buffer: &Entity<Buffer>,
 7675        buffer_position: language::Anchor,
 7676        cx: &App,
 7677    ) -> EditPredictionSettings {
 7678        if !self.mode.is_full()
 7679            || !self.show_edit_predictions_override.unwrap_or(true)
 7680            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7681        {
 7682            return EditPredictionSettings::Disabled;
 7683        }
 7684
 7685        let buffer = buffer.read(cx);
 7686
 7687        let file = buffer.file();
 7688
 7689        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7690            return EditPredictionSettings::Disabled;
 7691        };
 7692
 7693        let by_provider = matches!(
 7694            self.menu_edit_predictions_policy,
 7695            MenuEditPredictionsPolicy::ByProvider
 7696        );
 7697
 7698        let show_in_menu = by_provider
 7699            && self
 7700                .edit_prediction_provider
 7701                .as_ref()
 7702                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7703
 7704        let preview_requires_modifier =
 7705            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7706
 7707        EditPredictionSettings::Enabled {
 7708            show_in_menu,
 7709            preview_requires_modifier,
 7710        }
 7711    }
 7712
 7713    fn should_show_edit_predictions(&self) -> bool {
 7714        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7715    }
 7716
 7717    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7718        matches!(
 7719            self.edit_prediction_preview,
 7720            EditPredictionPreview::Active { .. }
 7721        )
 7722    }
 7723
 7724    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7725        let cursor = self.selections.newest_anchor().head();
 7726        if let Some((buffer, cursor_position)) =
 7727            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7728        {
 7729            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7730        } else {
 7731            false
 7732        }
 7733    }
 7734
 7735    pub fn supports_minimap(&self, cx: &App) -> bool {
 7736        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7737    }
 7738
 7739    fn edit_predictions_enabled_in_buffer(
 7740        &self,
 7741        buffer: &Entity<Buffer>,
 7742        buffer_position: language::Anchor,
 7743        cx: &App,
 7744    ) -> bool {
 7745        maybe!({
 7746            if self.read_only(cx) {
 7747                return Some(false);
 7748            }
 7749            let provider = self.edit_prediction_provider()?;
 7750            if !provider.is_enabled(buffer, buffer_position, cx) {
 7751                return Some(false);
 7752            }
 7753            let buffer = buffer.read(cx);
 7754            let Some(file) = buffer.file() else {
 7755                return Some(true);
 7756            };
 7757            let settings = all_language_settings(Some(file), cx);
 7758            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7759        })
 7760        .unwrap_or(false)
 7761    }
 7762
 7763    pub fn show_edit_prediction(
 7764        &mut self,
 7765        _: &ShowEditPrediction,
 7766        window: &mut Window,
 7767        cx: &mut Context<Self>,
 7768    ) {
 7769        if !self.has_active_edit_prediction() {
 7770            self.refresh_edit_prediction(false, true, window, cx);
 7771            return;
 7772        }
 7773
 7774        self.update_visible_edit_prediction(window, cx);
 7775    }
 7776
 7777    pub fn display_cursor_names(
 7778        &mut self,
 7779        _: &DisplayCursorNames,
 7780        window: &mut Window,
 7781        cx: &mut Context<Self>,
 7782    ) {
 7783        self.show_cursor_names(window, cx);
 7784    }
 7785
 7786    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7787        self.show_cursor_names = true;
 7788        cx.notify();
 7789        cx.spawn_in(window, async move |this, cx| {
 7790            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7791            this.update(cx, |this, cx| {
 7792                this.show_cursor_names = false;
 7793                cx.notify()
 7794            })
 7795            .ok()
 7796        })
 7797        .detach();
 7798    }
 7799
 7800    pub fn accept_partial_edit_prediction(
 7801        &mut self,
 7802        granularity: EditPredictionGranularity,
 7803        window: &mut Window,
 7804        cx: &mut Context<Self>,
 7805    ) {
 7806        if self.show_edit_predictions_in_menu() {
 7807            self.hide_context_menu(window, cx);
 7808        }
 7809
 7810        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7811            return;
 7812        };
 7813
 7814        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7815            return;
 7816        }
 7817
 7818        match &active_edit_prediction.completion {
 7819            EditPrediction::MoveWithin { target, .. } => {
 7820                let target = *target;
 7821
 7822                if matches!(granularity, EditPredictionGranularity::Full) {
 7823                    if let Some(position_map) = &self.last_position_map {
 7824                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7825                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7826
 7827                        if is_visible || !self.edit_prediction_requires_modifier() {
 7828                            self.unfold_ranges(&[target..target], true, false, cx);
 7829                            self.change_selections(
 7830                                SelectionEffects::scroll(Autoscroll::newest()),
 7831                                window,
 7832                                cx,
 7833                                |selections| {
 7834                                    selections.select_anchor_ranges([target..target]);
 7835                                },
 7836                            );
 7837                            self.clear_row_highlights::<EditPredictionPreview>();
 7838                            self.edit_prediction_preview
 7839                                .set_previous_scroll_position(None);
 7840                        } else {
 7841                            // Highlight and request scroll
 7842                            self.edit_prediction_preview
 7843                                .set_previous_scroll_position(Some(
 7844                                    position_map.snapshot.scroll_anchor,
 7845                                ));
 7846                            self.highlight_rows::<EditPredictionPreview>(
 7847                                target..target,
 7848                                cx.theme().colors().editor_highlighted_line_background,
 7849                                RowHighlightOptions {
 7850                                    autoscroll: true,
 7851                                    ..Default::default()
 7852                                },
 7853                                cx,
 7854                            );
 7855                            self.request_autoscroll(Autoscroll::fit(), cx);
 7856                        }
 7857                    }
 7858                } else {
 7859                    self.change_selections(
 7860                        SelectionEffects::scroll(Autoscroll::newest()),
 7861                        window,
 7862                        cx,
 7863                        |selections| {
 7864                            selections.select_anchor_ranges([target..target]);
 7865                        },
 7866                    );
 7867                }
 7868            }
 7869            EditPrediction::MoveOutside { snapshot, target } => {
 7870                if let Some(workspace) = self.workspace() {
 7871                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7872                        .detach_and_log_err(cx);
 7873                }
 7874            }
 7875            EditPrediction::Edit { edits, .. } => {
 7876                self.report_edit_prediction_event(
 7877                    active_edit_prediction.completion_id.clone(),
 7878                    true,
 7879                    cx,
 7880                );
 7881
 7882                match granularity {
 7883                    EditPredictionGranularity::Full => {
 7884                        if let Some(provider) = self.edit_prediction_provider() {
 7885                            provider.accept(cx);
 7886                        }
 7887
 7888                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7889                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7890                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7891
 7892                        self.buffer.update(cx, |buffer, cx| {
 7893                            buffer.edit(edits.iter().cloned(), None, cx)
 7894                        });
 7895
 7896                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7897                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7898                        });
 7899
 7900                        let selections = self.selections.disjoint_anchors_arc();
 7901                        if let Some(transaction_id_now) =
 7902                            self.buffer.read(cx).last_transaction_id(cx)
 7903                        {
 7904                            if transaction_id_prev != Some(transaction_id_now) {
 7905                                self.selection_history
 7906                                    .insert_transaction(transaction_id_now, selections);
 7907                            }
 7908                        }
 7909
 7910                        self.update_visible_edit_prediction(window, cx);
 7911                        if self.active_edit_prediction.is_none() {
 7912                            self.refresh_edit_prediction(true, true, window, cx);
 7913                        }
 7914                        cx.notify();
 7915                    }
 7916                    _ => {
 7917                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7918                        let cursor_offset = self
 7919                            .selections
 7920                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7921                            .head();
 7922
 7923                        let insertion = edits.iter().find_map(|(range, text)| {
 7924                            let range = range.to_offset(&snapshot);
 7925                            if range.is_empty() && range.start == cursor_offset {
 7926                                Some(text)
 7927                            } else {
 7928                                None
 7929                            }
 7930                        });
 7931
 7932                        if let Some(text) = insertion {
 7933                            let text_to_insert = match granularity {
 7934                                EditPredictionGranularity::Word => {
 7935                                    let mut partial = text
 7936                                        .chars()
 7937                                        .by_ref()
 7938                                        .take_while(|c| c.is_alphabetic())
 7939                                        .collect::<String>();
 7940                                    if partial.is_empty() {
 7941                                        partial = text
 7942                                            .chars()
 7943                                            .by_ref()
 7944                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7945                                            .collect::<String>();
 7946                                    }
 7947                                    partial
 7948                                }
 7949                                EditPredictionGranularity::Line => {
 7950                                    if let Some(line) = text.split_inclusive('\n').next() {
 7951                                        line.to_string()
 7952                                    } else {
 7953                                        text.to_string()
 7954                                    }
 7955                                }
 7956                                EditPredictionGranularity::Full => unreachable!(),
 7957                            };
 7958
 7959                            cx.emit(EditorEvent::InputHandled {
 7960                                utf16_range_to_replace: None,
 7961                                text: text_to_insert.clone().into(),
 7962                            });
 7963
 7964                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7965                            self.refresh_edit_prediction(true, true, window, cx);
 7966                            cx.notify();
 7967                        } else {
 7968                            self.accept_partial_edit_prediction(
 7969                                EditPredictionGranularity::Full,
 7970                                window,
 7971                                cx,
 7972                            );
 7973                        }
 7974                    }
 7975                }
 7976            }
 7977        }
 7978
 7979        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7980    }
 7981
 7982    pub fn accept_next_word_edit_prediction(
 7983        &mut self,
 7984        _: &AcceptNextWordEditPrediction,
 7985        window: &mut Window,
 7986        cx: &mut Context<Self>,
 7987    ) {
 7988        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7989    }
 7990
 7991    pub fn accept_next_line_edit_prediction(
 7992        &mut self,
 7993        _: &AcceptNextLineEditPrediction,
 7994        window: &mut Window,
 7995        cx: &mut Context<Self>,
 7996    ) {
 7997        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7998    }
 7999
 8000    pub fn accept_edit_prediction(
 8001        &mut self,
 8002        _: &AcceptEditPrediction,
 8003        window: &mut Window,
 8004        cx: &mut Context<Self>,
 8005    ) {
 8006        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 8007    }
 8008
 8009    fn discard_edit_prediction(
 8010        &mut self,
 8011        should_report_edit_prediction_event: bool,
 8012        cx: &mut Context<Self>,
 8013    ) -> bool {
 8014        if should_report_edit_prediction_event {
 8015            let completion_id = self
 8016                .active_edit_prediction
 8017                .as_ref()
 8018                .and_then(|active_completion| active_completion.completion_id.clone());
 8019
 8020            self.report_edit_prediction_event(completion_id, false, cx);
 8021        }
 8022
 8023        if let Some(provider) = self.edit_prediction_provider() {
 8024            provider.discard(cx);
 8025        }
 8026
 8027        self.take_active_edit_prediction(cx)
 8028    }
 8029
 8030    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 8031        let Some(provider) = self.edit_prediction_provider() else {
 8032            return;
 8033        };
 8034
 8035        let Some((_, buffer, _)) = self
 8036            .buffer
 8037            .read(cx)
 8038            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 8039        else {
 8040            return;
 8041        };
 8042
 8043        let extension = buffer
 8044            .read(cx)
 8045            .file()
 8046            .and_then(|file| Some(file.path().extension()?.to_string()));
 8047
 8048        let event_type = match accepted {
 8049            true => "Edit Prediction Accepted",
 8050            false => "Edit Prediction Discarded",
 8051        };
 8052        telemetry::event!(
 8053            event_type,
 8054            provider = provider.name(),
 8055            prediction_id = id,
 8056            suggestion_accepted = accepted,
 8057            file_extension = extension,
 8058        );
 8059    }
 8060
 8061    fn open_editor_at_anchor(
 8062        snapshot: &language::BufferSnapshot,
 8063        target: language::Anchor,
 8064        workspace: &Entity<Workspace>,
 8065        window: &mut Window,
 8066        cx: &mut App,
 8067    ) -> Task<Result<()>> {
 8068        workspace.update(cx, |workspace, cx| {
 8069            let path = snapshot.file().map(|file| file.full_path(cx));
 8070            let Some(path) =
 8071                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 8072            else {
 8073                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 8074            };
 8075            let target = text::ToPoint::to_point(&target, snapshot);
 8076            let item = workspace.open_path(path, None, true, window, cx);
 8077            window.spawn(cx, async move |cx| {
 8078                let Some(editor) = item.await?.downcast::<Editor>() else {
 8079                    return Ok(());
 8080                };
 8081                editor
 8082                    .update_in(cx, |editor, window, cx| {
 8083                        editor.go_to_singleton_buffer_point(target, window, cx);
 8084                    })
 8085                    .ok();
 8086                anyhow::Ok(())
 8087            })
 8088        })
 8089    }
 8090
 8091    pub fn has_active_edit_prediction(&self) -> bool {
 8092        self.active_edit_prediction.is_some()
 8093    }
 8094
 8095    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 8096        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 8097            return false;
 8098        };
 8099
 8100        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 8101        self.clear_highlights::<EditPredictionHighlight>(cx);
 8102        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 8103        true
 8104    }
 8105
 8106    /// Returns true when we're displaying the edit prediction popover below the cursor
 8107    /// like we are not previewing and the LSP autocomplete menu is visible
 8108    /// or we are in `when_holding_modifier` mode.
 8109    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 8110        if self.edit_prediction_preview_is_active()
 8111            || !self.show_edit_predictions_in_menu()
 8112            || !self.edit_predictions_enabled()
 8113        {
 8114            return false;
 8115        }
 8116
 8117        if self.has_visible_completions_menu() {
 8118            return true;
 8119        }
 8120
 8121        has_completion && self.edit_prediction_requires_modifier()
 8122    }
 8123
 8124    fn handle_modifiers_changed(
 8125        &mut self,
 8126        modifiers: Modifiers,
 8127        position_map: &PositionMap,
 8128        window: &mut Window,
 8129        cx: &mut Context<Self>,
 8130    ) {
 8131        // Ensure that the edit prediction preview is updated, even when not
 8132        // enabled, if there's an active edit prediction preview.
 8133        if self.show_edit_predictions_in_menu()
 8134            || matches!(
 8135                self.edit_prediction_preview,
 8136                EditPredictionPreview::Active { .. }
 8137            )
 8138        {
 8139            self.update_edit_prediction_preview(&modifiers, window, cx);
 8140        }
 8141
 8142        self.update_selection_mode(&modifiers, position_map, window, cx);
 8143
 8144        let mouse_position = window.mouse_position();
 8145        if !position_map.text_hitbox.is_hovered(window) {
 8146            return;
 8147        }
 8148
 8149        self.update_hovered_link(
 8150            position_map.point_for_position(mouse_position),
 8151            &position_map.snapshot,
 8152            modifiers,
 8153            window,
 8154            cx,
 8155        )
 8156    }
 8157
 8158    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8159        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8160            MultiCursorModifier::Alt => modifiers.secondary(),
 8161            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8162        }
 8163    }
 8164
 8165    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8166        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8167            MultiCursorModifier::Alt => modifiers.alt,
 8168            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8169        }
 8170    }
 8171
 8172    fn columnar_selection_mode(
 8173        modifiers: &Modifiers,
 8174        cx: &mut Context<Self>,
 8175    ) -> Option<ColumnarMode> {
 8176        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8177            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8178                Some(ColumnarMode::FromMouse)
 8179            } else if Self::is_alt_pressed(modifiers, cx) {
 8180                Some(ColumnarMode::FromSelection)
 8181            } else {
 8182                None
 8183            }
 8184        } else {
 8185            None
 8186        }
 8187    }
 8188
 8189    fn update_selection_mode(
 8190        &mut self,
 8191        modifiers: &Modifiers,
 8192        position_map: &PositionMap,
 8193        window: &mut Window,
 8194        cx: &mut Context<Self>,
 8195    ) {
 8196        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8197            return;
 8198        };
 8199        if self.selections.pending_anchor().is_none() {
 8200            return;
 8201        }
 8202
 8203        let mouse_position = window.mouse_position();
 8204        let point_for_position = position_map.point_for_position(mouse_position);
 8205        let position = point_for_position.previous_valid;
 8206
 8207        self.select(
 8208            SelectPhase::BeginColumnar {
 8209                position,
 8210                reset: false,
 8211                mode,
 8212                goal_column: point_for_position.exact_unclipped.column(),
 8213            },
 8214            window,
 8215            cx,
 8216        );
 8217    }
 8218
 8219    fn update_edit_prediction_preview(
 8220        &mut self,
 8221        modifiers: &Modifiers,
 8222        window: &mut Window,
 8223        cx: &mut Context<Self>,
 8224    ) {
 8225        let mut modifiers_held = false;
 8226
 8227        // Check bindings for all granularities.
 8228        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 8229        let granularities = [
 8230            EditPredictionGranularity::Full,
 8231            EditPredictionGranularity::Line,
 8232            EditPredictionGranularity::Word,
 8233        ];
 8234
 8235        for granularity in granularities {
 8236            if let Some(keystroke) = self
 8237                .accept_edit_prediction_keybind(granularity, window, cx)
 8238                .keystroke()
 8239            {
 8240                modifiers_held = modifiers_held
 8241                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8242            }
 8243        }
 8244
 8245        if modifiers_held {
 8246            if matches!(
 8247                self.edit_prediction_preview,
 8248                EditPredictionPreview::Inactive { .. }
 8249            ) {
 8250                self.edit_prediction_preview = EditPredictionPreview::Active {
 8251                    previous_scroll_position: None,
 8252                    since: Instant::now(),
 8253                };
 8254
 8255                self.update_visible_edit_prediction(window, cx);
 8256                cx.notify();
 8257            }
 8258        } else if let EditPredictionPreview::Active {
 8259            previous_scroll_position,
 8260            since,
 8261        } = self.edit_prediction_preview
 8262        {
 8263            if let (Some(previous_scroll_position), Some(position_map)) =
 8264                (previous_scroll_position, self.last_position_map.as_ref())
 8265            {
 8266                self.set_scroll_position(
 8267                    previous_scroll_position
 8268                        .scroll_position(&position_map.snapshot.display_snapshot),
 8269                    window,
 8270                    cx,
 8271                );
 8272            }
 8273
 8274            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8275                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8276            };
 8277            self.clear_row_highlights::<EditPredictionPreview>();
 8278            self.update_visible_edit_prediction(window, cx);
 8279            cx.notify();
 8280        }
 8281    }
 8282
 8283    fn update_visible_edit_prediction(
 8284        &mut self,
 8285        _window: &mut Window,
 8286        cx: &mut Context<Self>,
 8287    ) -> Option<()> {
 8288        if DisableAiSettings::get_global(cx).disable_ai {
 8289            return None;
 8290        }
 8291
 8292        if self.ime_transaction.is_some() {
 8293            self.discard_edit_prediction(false, cx);
 8294            return None;
 8295        }
 8296
 8297        let selection = self.selections.newest_anchor();
 8298        let cursor = selection.head();
 8299        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8300        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8301        let excerpt_id = cursor.excerpt_id;
 8302
 8303        let show_in_menu = self.show_edit_predictions_in_menu();
 8304        let completions_menu_has_precedence = !show_in_menu
 8305            && (self.context_menu.borrow().is_some()
 8306                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8307
 8308        if completions_menu_has_precedence
 8309            || !offset_selection.is_empty()
 8310            || self
 8311                .active_edit_prediction
 8312                .as_ref()
 8313                .is_some_and(|completion| {
 8314                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8315                        return false;
 8316                    };
 8317                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8318                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8319                    !invalidation_range.contains(&offset_selection.head())
 8320                })
 8321        {
 8322            self.discard_edit_prediction(false, cx);
 8323            return None;
 8324        }
 8325
 8326        self.take_active_edit_prediction(cx);
 8327        let Some(provider) = self.edit_prediction_provider() else {
 8328            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8329            return None;
 8330        };
 8331
 8332        let (buffer, cursor_buffer_position) =
 8333            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8334
 8335        self.edit_prediction_settings =
 8336            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8337
 8338        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8339
 8340        if self.edit_prediction_indent_conflict {
 8341            let cursor_point = cursor.to_point(&multibuffer);
 8342            let mut suggested_indent = None;
 8343            multibuffer.suggested_indents_callback(
 8344                cursor_point.row..cursor_point.row + 1,
 8345                |_, indent| {
 8346                    suggested_indent = Some(indent);
 8347                    ControlFlow::Break(())
 8348                },
 8349                cx,
 8350            );
 8351
 8352            if let Some(indent) = suggested_indent
 8353                && indent.len == cursor_point.column
 8354            {
 8355                self.edit_prediction_indent_conflict = false;
 8356            }
 8357        }
 8358
 8359        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8360
 8361        let (completion_id, edits, edit_preview) = match edit_prediction {
 8362            edit_prediction_types::EditPrediction::Local {
 8363                id,
 8364                edits,
 8365                edit_preview,
 8366            } => (id, edits, edit_preview),
 8367            edit_prediction_types::EditPrediction::Jump {
 8368                id,
 8369                snapshot,
 8370                target,
 8371            } => {
 8372                if let Some(provider) = &self.edit_prediction_provider {
 8373                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8374                }
 8375                self.stale_edit_prediction_in_menu = None;
 8376                self.active_edit_prediction = Some(EditPredictionState {
 8377                    inlay_ids: vec![],
 8378                    completion: EditPrediction::MoveOutside { snapshot, target },
 8379                    completion_id: id,
 8380                    invalidation_range: None,
 8381                });
 8382                cx.notify();
 8383                return Some(());
 8384            }
 8385        };
 8386
 8387        let edits = edits
 8388            .into_iter()
 8389            .flat_map(|(range, new_text)| {
 8390                Some((
 8391                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8392                    new_text,
 8393                ))
 8394            })
 8395            .collect::<Vec<_>>();
 8396        if edits.is_empty() {
 8397            return None;
 8398        }
 8399
 8400        let first_edit_start = edits.first().unwrap().0.start;
 8401        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8402        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8403
 8404        let last_edit_end = edits.last().unwrap().0.end;
 8405        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8406        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8407
 8408        let cursor_row = cursor.to_point(&multibuffer).row;
 8409
 8410        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8411
 8412        let mut inlay_ids = Vec::new();
 8413        let invalidation_row_range;
 8414        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8415            Some(cursor_row..edit_end_row)
 8416        } else if cursor_row > edit_end_row {
 8417            Some(edit_start_row..cursor_row)
 8418        } else {
 8419            None
 8420        };
 8421        let supports_jump = self
 8422            .edit_prediction_provider
 8423            .as_ref()
 8424            .map(|provider| provider.provider.supports_jump_to_edit())
 8425            .unwrap_or(true);
 8426
 8427        let is_move = supports_jump
 8428            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8429        let completion = if is_move {
 8430            if let Some(provider) = &self.edit_prediction_provider {
 8431                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8432            }
 8433            invalidation_row_range =
 8434                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8435            let target = first_edit_start;
 8436            EditPrediction::MoveWithin { target, snapshot }
 8437        } else {
 8438            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8439                && !self.edit_predictions_hidden_for_vim_mode;
 8440
 8441            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8442                if provider.show_tab_accept_marker() {
 8443                    EditDisplayMode::TabAccept
 8444                } else {
 8445                    EditDisplayMode::Inline
 8446                }
 8447            } else {
 8448                EditDisplayMode::DiffPopover
 8449            };
 8450
 8451            if show_completions_in_buffer {
 8452                if let Some(provider) = &self.edit_prediction_provider {
 8453                    let suggestion_display_type = match display_mode {
 8454                        EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8455                        EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8456                            SuggestionDisplayType::GhostText
 8457                        }
 8458                    };
 8459                    provider.provider.did_show(suggestion_display_type, cx);
 8460                }
 8461                if edits
 8462                    .iter()
 8463                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8464                {
 8465                    let mut inlays = Vec::new();
 8466                    for (range, new_text) in &edits {
 8467                        let inlay = Inlay::edit_prediction(
 8468                            post_inc(&mut self.next_inlay_id),
 8469                            range.start,
 8470                            new_text.as_ref(),
 8471                        );
 8472                        inlay_ids.push(inlay.id);
 8473                        inlays.push(inlay);
 8474                    }
 8475
 8476                    self.splice_inlays(&[], inlays, cx);
 8477                } else {
 8478                    let background_color = cx.theme().status().deleted_background;
 8479                    self.highlight_text::<EditPredictionHighlight>(
 8480                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8481                        HighlightStyle {
 8482                            background_color: Some(background_color),
 8483                            ..Default::default()
 8484                        },
 8485                        cx,
 8486                    );
 8487                }
 8488            }
 8489
 8490            invalidation_row_range = edit_start_row..edit_end_row;
 8491
 8492            EditPrediction::Edit {
 8493                edits,
 8494                edit_preview,
 8495                display_mode,
 8496                snapshot,
 8497            }
 8498        };
 8499
 8500        let invalidation_range = multibuffer
 8501            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8502            ..multibuffer.anchor_after(Point::new(
 8503                invalidation_row_range.end,
 8504                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8505            ));
 8506
 8507        self.stale_edit_prediction_in_menu = None;
 8508        self.active_edit_prediction = Some(EditPredictionState {
 8509            inlay_ids,
 8510            completion,
 8511            completion_id,
 8512            invalidation_range: Some(invalidation_range),
 8513        });
 8514
 8515        cx.notify();
 8516
 8517        Some(())
 8518    }
 8519
 8520    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8521        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8522    }
 8523
 8524    fn clear_tasks(&mut self) {
 8525        self.tasks.clear()
 8526    }
 8527
 8528    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8529        if self.tasks.insert(key, value).is_some() {
 8530            // This case should hopefully be rare, but just in case...
 8531            log::error!(
 8532                "multiple different run targets found on a single line, only the last target will be rendered"
 8533            )
 8534        }
 8535    }
 8536
 8537    /// Get all display points of breakpoints that will be rendered within editor
 8538    ///
 8539    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8540    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8541    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8542    fn active_breakpoints(
 8543        &self,
 8544        range: Range<DisplayRow>,
 8545        window: &mut Window,
 8546        cx: &mut Context<Self>,
 8547    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8548        let mut breakpoint_display_points = HashMap::default();
 8549
 8550        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8551            return breakpoint_display_points;
 8552        };
 8553
 8554        let snapshot = self.snapshot(window, cx);
 8555
 8556        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8557        let Some(project) = self.project() else {
 8558            return breakpoint_display_points;
 8559        };
 8560
 8561        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8562            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8563
 8564        for (buffer_snapshot, range, excerpt_id) in
 8565            multi_buffer_snapshot.range_to_buffer_ranges(range.start..=range.end)
 8566        {
 8567            let Some(buffer) = project
 8568                .read(cx)
 8569                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8570            else {
 8571                continue;
 8572            };
 8573            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8574                &buffer,
 8575                Some(
 8576                    buffer_snapshot.anchor_before(range.start)
 8577                        ..buffer_snapshot.anchor_after(range.end),
 8578                ),
 8579                buffer_snapshot,
 8580                cx,
 8581            );
 8582            for (breakpoint, state) in breakpoints {
 8583                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8584                let position = multi_buffer_anchor
 8585                    .to_point(&multi_buffer_snapshot)
 8586                    .to_display_point(&snapshot);
 8587
 8588                breakpoint_display_points.insert(
 8589                    position.row(),
 8590                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8591                );
 8592            }
 8593        }
 8594
 8595        breakpoint_display_points
 8596    }
 8597
 8598    fn breakpoint_context_menu(
 8599        &self,
 8600        anchor: Anchor,
 8601        window: &mut Window,
 8602        cx: &mut Context<Self>,
 8603    ) -> Entity<ui::ContextMenu> {
 8604        let weak_editor = cx.weak_entity();
 8605        let focus_handle = self.focus_handle(cx);
 8606
 8607        let row = self
 8608            .buffer
 8609            .read(cx)
 8610            .snapshot(cx)
 8611            .summary_for_anchor::<Point>(&anchor)
 8612            .row;
 8613
 8614        let breakpoint = self
 8615            .breakpoint_at_row(row, window, cx)
 8616            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8617
 8618        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8619            "Edit Log Breakpoint"
 8620        } else {
 8621            "Set Log Breakpoint"
 8622        };
 8623
 8624        let condition_breakpoint_msg = if breakpoint
 8625            .as_ref()
 8626            .is_some_and(|bp| bp.1.condition.is_some())
 8627        {
 8628            "Edit Condition Breakpoint"
 8629        } else {
 8630            "Set Condition Breakpoint"
 8631        };
 8632
 8633        let hit_condition_breakpoint_msg = if breakpoint
 8634            .as_ref()
 8635            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8636        {
 8637            "Edit Hit Condition Breakpoint"
 8638        } else {
 8639            "Set Hit Condition Breakpoint"
 8640        };
 8641
 8642        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8643            "Unset Breakpoint"
 8644        } else {
 8645            "Set Breakpoint"
 8646        };
 8647
 8648        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8649
 8650        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8651            BreakpointState::Enabled => Some("Disable"),
 8652            BreakpointState::Disabled => Some("Enable"),
 8653        });
 8654
 8655        let (anchor, breakpoint) =
 8656            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8657
 8658        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8659            menu.on_blur_subscription(Subscription::new(|| {}))
 8660                .context(focus_handle)
 8661                .when(run_to_cursor, |this| {
 8662                    let weak_editor = weak_editor.clone();
 8663                    this.entry("Run to cursor", None, move |window, cx| {
 8664                        weak_editor
 8665                            .update(cx, |editor, cx| {
 8666                                editor.change_selections(
 8667                                    SelectionEffects::no_scroll(),
 8668                                    window,
 8669                                    cx,
 8670                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8671                                );
 8672                            })
 8673                            .ok();
 8674
 8675                        window.dispatch_action(Box::new(RunToCursor), cx);
 8676                    })
 8677                    .separator()
 8678                })
 8679                .when_some(toggle_state_msg, |this, msg| {
 8680                    this.entry(msg, None, {
 8681                        let weak_editor = weak_editor.clone();
 8682                        let breakpoint = breakpoint.clone();
 8683                        move |_window, cx| {
 8684                            weak_editor
 8685                                .update(cx, |this, cx| {
 8686                                    this.edit_breakpoint_at_anchor(
 8687                                        anchor,
 8688                                        breakpoint.as_ref().clone(),
 8689                                        BreakpointEditAction::InvertState,
 8690                                        cx,
 8691                                    );
 8692                                })
 8693                                .log_err();
 8694                        }
 8695                    })
 8696                })
 8697                .entry(set_breakpoint_msg, None, {
 8698                    let weak_editor = weak_editor.clone();
 8699                    let breakpoint = breakpoint.clone();
 8700                    move |_window, cx| {
 8701                        weak_editor
 8702                            .update(cx, |this, cx| {
 8703                                this.edit_breakpoint_at_anchor(
 8704                                    anchor,
 8705                                    breakpoint.as_ref().clone(),
 8706                                    BreakpointEditAction::Toggle,
 8707                                    cx,
 8708                                );
 8709                            })
 8710                            .log_err();
 8711                    }
 8712                })
 8713                .entry(log_breakpoint_msg, None, {
 8714                    let breakpoint = breakpoint.clone();
 8715                    let weak_editor = weak_editor.clone();
 8716                    move |window, cx| {
 8717                        weak_editor
 8718                            .update(cx, |this, cx| {
 8719                                this.add_edit_breakpoint_block(
 8720                                    anchor,
 8721                                    breakpoint.as_ref(),
 8722                                    BreakpointPromptEditAction::Log,
 8723                                    window,
 8724                                    cx,
 8725                                );
 8726                            })
 8727                            .log_err();
 8728                    }
 8729                })
 8730                .entry(condition_breakpoint_msg, None, {
 8731                    let breakpoint = breakpoint.clone();
 8732                    let weak_editor = weak_editor.clone();
 8733                    move |window, cx| {
 8734                        weak_editor
 8735                            .update(cx, |this, cx| {
 8736                                this.add_edit_breakpoint_block(
 8737                                    anchor,
 8738                                    breakpoint.as_ref(),
 8739                                    BreakpointPromptEditAction::Condition,
 8740                                    window,
 8741                                    cx,
 8742                                );
 8743                            })
 8744                            .log_err();
 8745                    }
 8746                })
 8747                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8748                    weak_editor
 8749                        .update(cx, |this, cx| {
 8750                            this.add_edit_breakpoint_block(
 8751                                anchor,
 8752                                breakpoint.as_ref(),
 8753                                BreakpointPromptEditAction::HitCondition,
 8754                                window,
 8755                                cx,
 8756                            );
 8757                        })
 8758                        .log_err();
 8759                })
 8760        })
 8761    }
 8762
 8763    fn render_breakpoint(
 8764        &self,
 8765        position: Anchor,
 8766        row: DisplayRow,
 8767        breakpoint: &Breakpoint,
 8768        state: Option<BreakpointSessionState>,
 8769        cx: &mut Context<Self>,
 8770    ) -> IconButton {
 8771        let is_rejected = state.is_some_and(|s| !s.verified);
 8772        // Is it a breakpoint that shows up when hovering over gutter?
 8773        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8774            (false, false),
 8775            |PhantomBreakpointIndicator {
 8776                 is_active,
 8777                 display_row,
 8778                 collides_with_existing_breakpoint,
 8779             }| {
 8780                (
 8781                    is_active && display_row == row,
 8782                    collides_with_existing_breakpoint,
 8783                )
 8784            },
 8785        );
 8786
 8787        let (color, icon) = {
 8788            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8789                (false, false) => ui::IconName::DebugBreakpoint,
 8790                (true, false) => ui::IconName::DebugLogBreakpoint,
 8791                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8792                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8793            };
 8794
 8795            let theme_colors = cx.theme().colors();
 8796
 8797            let color = if is_phantom {
 8798                if collides_with_existing {
 8799                    Color::Custom(
 8800                        theme_colors
 8801                            .debugger_accent
 8802                            .blend(theme_colors.text.opacity(0.6)),
 8803                    )
 8804                } else {
 8805                    Color::Hint
 8806                }
 8807            } else if is_rejected {
 8808                Color::Disabled
 8809            } else {
 8810                Color::Debugger
 8811            };
 8812
 8813            (color, icon)
 8814        };
 8815
 8816        let breakpoint = Arc::from(breakpoint.clone());
 8817
 8818        let alt_as_text = gpui::Keystroke {
 8819            modifiers: Modifiers::secondary_key(),
 8820            ..Default::default()
 8821        };
 8822        let primary_action_text = if breakpoint.is_disabled() {
 8823            "Enable breakpoint"
 8824        } else if is_phantom && !collides_with_existing {
 8825            "Set breakpoint"
 8826        } else {
 8827            "Unset breakpoint"
 8828        };
 8829        let focus_handle = self.focus_handle.clone();
 8830
 8831        let meta = if is_rejected {
 8832            SharedString::from("No executable code is associated with this line.")
 8833        } else if collides_with_existing && !breakpoint.is_disabled() {
 8834            SharedString::from(format!(
 8835                "{alt_as_text}-click to disable,\nright-click for more options."
 8836            ))
 8837        } else {
 8838            SharedString::from("Right-click for more options.")
 8839        };
 8840        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8841            .icon_size(IconSize::XSmall)
 8842            .size(ui::ButtonSize::None)
 8843            .when(is_rejected, |this| {
 8844                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8845            })
 8846            .icon_color(color)
 8847            .style(ButtonStyle::Transparent)
 8848            .on_click(cx.listener({
 8849                move |editor, event: &ClickEvent, window, cx| {
 8850                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8851                        BreakpointEditAction::InvertState
 8852                    } else {
 8853                        BreakpointEditAction::Toggle
 8854                    };
 8855
 8856                    window.focus(&editor.focus_handle(cx), cx);
 8857                    editor.edit_breakpoint_at_anchor(
 8858                        position,
 8859                        breakpoint.as_ref().clone(),
 8860                        edit_action,
 8861                        cx,
 8862                    );
 8863                }
 8864            }))
 8865            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8866                editor.set_breakpoint_context_menu(
 8867                    row,
 8868                    Some(position),
 8869                    event.position(),
 8870                    window,
 8871                    cx,
 8872                );
 8873            }))
 8874            .tooltip(move |_window, cx| {
 8875                Tooltip::with_meta_in(
 8876                    primary_action_text,
 8877                    Some(&ToggleBreakpoint),
 8878                    meta.clone(),
 8879                    &focus_handle,
 8880                    cx,
 8881                )
 8882            })
 8883    }
 8884
 8885    fn build_tasks_context(
 8886        project: &Entity<Project>,
 8887        buffer: &Entity<Buffer>,
 8888        buffer_row: u32,
 8889        tasks: &Arc<RunnableTasks>,
 8890        cx: &mut Context<Self>,
 8891    ) -> Task<Option<task::TaskContext>> {
 8892        let position = Point::new(buffer_row, tasks.column);
 8893        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8894        let location = Location {
 8895            buffer: buffer.clone(),
 8896            range: range_start..range_start,
 8897        };
 8898        // Fill in the environmental variables from the tree-sitter captures
 8899        let mut captured_task_variables = TaskVariables::default();
 8900        for (capture_name, value) in tasks.extra_variables.clone() {
 8901            captured_task_variables.insert(
 8902                task::VariableName::Custom(capture_name.into()),
 8903                value.clone(),
 8904            );
 8905        }
 8906        project.update(cx, |project, cx| {
 8907            project.task_store().update(cx, |task_store, cx| {
 8908                task_store.task_context_for_location(captured_task_variables, location, cx)
 8909            })
 8910        })
 8911    }
 8912
 8913    pub fn spawn_nearest_task(
 8914        &mut self,
 8915        action: &SpawnNearestTask,
 8916        window: &mut Window,
 8917        cx: &mut Context<Self>,
 8918    ) {
 8919        let Some((workspace, _)) = self.workspace.clone() else {
 8920            return;
 8921        };
 8922        let Some(project) = self.project.clone() else {
 8923            return;
 8924        };
 8925
 8926        // Try to find a closest, enclosing node using tree-sitter that has a task
 8927        let Some((buffer, buffer_row, tasks)) = self
 8928            .find_enclosing_node_task(cx)
 8929            // Or find the task that's closest in row-distance.
 8930            .or_else(|| self.find_closest_task(cx))
 8931        else {
 8932            return;
 8933        };
 8934
 8935        let reveal_strategy = action.reveal;
 8936        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8937        cx.spawn_in(window, async move |_, cx| {
 8938            let context = task_context.await?;
 8939            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8940
 8941            let resolved = &mut resolved_task.resolved;
 8942            resolved.reveal = reveal_strategy;
 8943
 8944            workspace
 8945                .update_in(cx, |workspace, window, cx| {
 8946                    workspace.schedule_resolved_task(
 8947                        task_source_kind,
 8948                        resolved_task,
 8949                        false,
 8950                        window,
 8951                        cx,
 8952                    );
 8953                })
 8954                .ok()
 8955        })
 8956        .detach();
 8957    }
 8958
 8959    fn find_closest_task(
 8960        &mut self,
 8961        cx: &mut Context<Self>,
 8962    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8963        let cursor_row = self
 8964            .selections
 8965            .newest_adjusted(&self.display_snapshot(cx))
 8966            .head()
 8967            .row;
 8968
 8969        let ((buffer_id, row), tasks) = self
 8970            .tasks
 8971            .iter()
 8972            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8973
 8974        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8975        let tasks = Arc::new(tasks.to_owned());
 8976        Some((buffer, *row, tasks))
 8977    }
 8978
 8979    fn find_enclosing_node_task(
 8980        &mut self,
 8981        cx: &mut Context<Self>,
 8982    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8983        let snapshot = self.buffer.read(cx).snapshot(cx);
 8984        let offset = self
 8985            .selections
 8986            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8987            .head();
 8988        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8989        let offset = excerpt.map_offset_to_buffer(offset);
 8990        let buffer_id = excerpt.buffer().remote_id();
 8991
 8992        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8993        let mut cursor = layer.node().walk();
 8994
 8995        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8996            if cursor.node().end_byte() == offset.0 {
 8997                cursor.goto_next_sibling();
 8998            }
 8999        }
 9000
 9001        // Ascend to the smallest ancestor that contains the range and has a task.
 9002        loop {
 9003            let node = cursor.node();
 9004            let node_range = node.byte_range();
 9005            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 9006
 9007            // Check if this node contains our offset
 9008            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 9009                // If it contains offset, check for task
 9010                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 9011                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 9012                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 9013                }
 9014            }
 9015
 9016            if !cursor.goto_parent() {
 9017                break;
 9018            }
 9019        }
 9020        None
 9021    }
 9022
 9023    fn render_run_indicator(
 9024        &self,
 9025        _style: &EditorStyle,
 9026        is_active: bool,
 9027        row: DisplayRow,
 9028        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 9029        cx: &mut Context<Self>,
 9030    ) -> IconButton {
 9031        let color = Color::Muted;
 9032        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 9033
 9034        IconButton::new(
 9035            ("run_indicator", row.0 as usize),
 9036            ui::IconName::PlayOutlined,
 9037        )
 9038        .shape(ui::IconButtonShape::Square)
 9039        .icon_size(IconSize::XSmall)
 9040        .icon_color(color)
 9041        .toggle_state(is_active)
 9042        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 9043            let quick_launch = match e {
 9044                ClickEvent::Keyboard(_) => true,
 9045                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 9046            };
 9047
 9048            window.focus(&editor.focus_handle(cx), cx);
 9049            editor.toggle_code_actions(
 9050                &ToggleCodeActions {
 9051                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 9052                    quick_launch,
 9053                },
 9054                window,
 9055                cx,
 9056            );
 9057        }))
 9058        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 9059            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 9060        }))
 9061    }
 9062
 9063    pub fn context_menu_visible(&self) -> bool {
 9064        !self.edit_prediction_preview_is_active()
 9065            && self
 9066                .context_menu
 9067                .borrow()
 9068                .as_ref()
 9069                .is_some_and(|menu| menu.visible())
 9070    }
 9071
 9072    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 9073        self.context_menu
 9074            .borrow()
 9075            .as_ref()
 9076            .map(|menu| menu.origin())
 9077    }
 9078
 9079    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 9080        self.context_menu_options = Some(options);
 9081    }
 9082
 9083    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 9084    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 9085
 9086    fn render_edit_prediction_popover(
 9087        &mut self,
 9088        text_bounds: &Bounds<Pixels>,
 9089        content_origin: gpui::Point<Pixels>,
 9090        right_margin: Pixels,
 9091        editor_snapshot: &EditorSnapshot,
 9092        visible_row_range: Range<DisplayRow>,
 9093        scroll_top: ScrollOffset,
 9094        scroll_bottom: ScrollOffset,
 9095        line_layouts: &[LineWithInvisibles],
 9096        line_height: Pixels,
 9097        scroll_position: gpui::Point<ScrollOffset>,
 9098        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9099        newest_selection_head: Option<DisplayPoint>,
 9100        editor_width: Pixels,
 9101        style: &EditorStyle,
 9102        window: &mut Window,
 9103        cx: &mut App,
 9104    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9105        if self.mode().is_minimap() {
 9106            return None;
 9107        }
 9108        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 9109
 9110        if self.edit_prediction_visible_in_cursor_popover(true) {
 9111            return None;
 9112        }
 9113
 9114        match &active_edit_prediction.completion {
 9115            EditPrediction::MoveWithin { target, .. } => {
 9116                let target_display_point = target.to_display_point(editor_snapshot);
 9117
 9118                if self.edit_prediction_requires_modifier() {
 9119                    if !self.edit_prediction_preview_is_active() {
 9120                        return None;
 9121                    }
 9122
 9123                    self.render_edit_prediction_modifier_jump_popover(
 9124                        text_bounds,
 9125                        content_origin,
 9126                        visible_row_range,
 9127                        line_layouts,
 9128                        line_height,
 9129                        scroll_pixel_position,
 9130                        newest_selection_head,
 9131                        target_display_point,
 9132                        window,
 9133                        cx,
 9134                    )
 9135                } else {
 9136                    self.render_edit_prediction_eager_jump_popover(
 9137                        text_bounds,
 9138                        content_origin,
 9139                        editor_snapshot,
 9140                        visible_row_range,
 9141                        scroll_top,
 9142                        scroll_bottom,
 9143                        line_height,
 9144                        scroll_pixel_position,
 9145                        target_display_point,
 9146                        editor_width,
 9147                        window,
 9148                        cx,
 9149                    )
 9150                }
 9151            }
 9152            EditPrediction::Edit {
 9153                display_mode: EditDisplayMode::Inline,
 9154                ..
 9155            } => None,
 9156            EditPrediction::Edit {
 9157                display_mode: EditDisplayMode::TabAccept,
 9158                edits,
 9159                ..
 9160            } => {
 9161                let range = &edits.first()?.0;
 9162                let target_display_point = range.end.to_display_point(editor_snapshot);
 9163
 9164                self.render_edit_prediction_end_of_line_popover(
 9165                    "Accept",
 9166                    editor_snapshot,
 9167                    visible_row_range,
 9168                    target_display_point,
 9169                    line_height,
 9170                    scroll_pixel_position,
 9171                    content_origin,
 9172                    editor_width,
 9173                    window,
 9174                    cx,
 9175                )
 9176            }
 9177            EditPrediction::Edit {
 9178                edits,
 9179                edit_preview,
 9180                display_mode: EditDisplayMode::DiffPopover,
 9181                snapshot,
 9182            } => self.render_edit_prediction_diff_popover(
 9183                text_bounds,
 9184                content_origin,
 9185                right_margin,
 9186                editor_snapshot,
 9187                visible_row_range,
 9188                line_layouts,
 9189                line_height,
 9190                scroll_position,
 9191                scroll_pixel_position,
 9192                newest_selection_head,
 9193                editor_width,
 9194                style,
 9195                edits,
 9196                edit_preview,
 9197                snapshot,
 9198                window,
 9199                cx,
 9200            ),
 9201            EditPrediction::MoveOutside { snapshot, .. } => {
 9202                let mut element = self
 9203                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9204                    .into_any();
 9205
 9206                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9207                let origin_x = text_bounds.size.width - size.width - px(30.);
 9208                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9209                element.prepaint_at(origin, window, cx);
 9210
 9211                Some((element, origin))
 9212            }
 9213        }
 9214    }
 9215
 9216    fn render_edit_prediction_modifier_jump_popover(
 9217        &mut self,
 9218        text_bounds: &Bounds<Pixels>,
 9219        content_origin: gpui::Point<Pixels>,
 9220        visible_row_range: Range<DisplayRow>,
 9221        line_layouts: &[LineWithInvisibles],
 9222        line_height: Pixels,
 9223        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9224        newest_selection_head: Option<DisplayPoint>,
 9225        target_display_point: DisplayPoint,
 9226        window: &mut Window,
 9227        cx: &mut App,
 9228    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9229        let scrolled_content_origin =
 9230            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9231
 9232        const SCROLL_PADDING_Y: Pixels = px(12.);
 9233
 9234        if target_display_point.row() < visible_row_range.start {
 9235            return self.render_edit_prediction_scroll_popover(
 9236                |_| SCROLL_PADDING_Y,
 9237                IconName::ArrowUp,
 9238                visible_row_range,
 9239                line_layouts,
 9240                newest_selection_head,
 9241                scrolled_content_origin,
 9242                window,
 9243                cx,
 9244            );
 9245        } else if target_display_point.row() >= visible_row_range.end {
 9246            return self.render_edit_prediction_scroll_popover(
 9247                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9248                IconName::ArrowDown,
 9249                visible_row_range,
 9250                line_layouts,
 9251                newest_selection_head,
 9252                scrolled_content_origin,
 9253                window,
 9254                cx,
 9255            );
 9256        }
 9257
 9258        const POLE_WIDTH: Pixels = px(2.);
 9259
 9260        let line_layout =
 9261            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9262        let target_column = target_display_point.column() as usize;
 9263
 9264        let target_x = line_layout.x_for_index(target_column);
 9265        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9266            - scroll_pixel_position.y;
 9267
 9268        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9269
 9270        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9271        border_color.l += 0.001;
 9272
 9273        let mut element = v_flex()
 9274            .items_end()
 9275            .when(flag_on_right, |el| el.items_start())
 9276            .child(if flag_on_right {
 9277                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9278                    .rounded_bl(px(0.))
 9279                    .rounded_tl(px(0.))
 9280                    .border_l_2()
 9281                    .border_color(border_color)
 9282            } else {
 9283                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9284                    .rounded_br(px(0.))
 9285                    .rounded_tr(px(0.))
 9286                    .border_r_2()
 9287                    .border_color(border_color)
 9288            })
 9289            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9290            .into_any();
 9291
 9292        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9293
 9294        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9295            - point(
 9296                if flag_on_right {
 9297                    POLE_WIDTH
 9298                } else {
 9299                    size.width - POLE_WIDTH
 9300                },
 9301                size.height - line_height,
 9302            );
 9303
 9304        origin.x = origin.x.max(content_origin.x);
 9305
 9306        element.prepaint_at(origin, window, cx);
 9307
 9308        Some((element, origin))
 9309    }
 9310
 9311    fn render_edit_prediction_scroll_popover(
 9312        &mut self,
 9313        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9314        scroll_icon: IconName,
 9315        visible_row_range: Range<DisplayRow>,
 9316        line_layouts: &[LineWithInvisibles],
 9317        newest_selection_head: Option<DisplayPoint>,
 9318        scrolled_content_origin: gpui::Point<Pixels>,
 9319        window: &mut Window,
 9320        cx: &mut App,
 9321    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9322        let mut element = self
 9323            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9324            .into_any();
 9325
 9326        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9327
 9328        let cursor = newest_selection_head?;
 9329        let cursor_row_layout =
 9330            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9331        let cursor_column = cursor.column() as usize;
 9332
 9333        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9334
 9335        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9336
 9337        element.prepaint_at(origin, window, cx);
 9338        Some((element, origin))
 9339    }
 9340
 9341    fn render_edit_prediction_eager_jump_popover(
 9342        &mut self,
 9343        text_bounds: &Bounds<Pixels>,
 9344        content_origin: gpui::Point<Pixels>,
 9345        editor_snapshot: &EditorSnapshot,
 9346        visible_row_range: Range<DisplayRow>,
 9347        scroll_top: ScrollOffset,
 9348        scroll_bottom: ScrollOffset,
 9349        line_height: Pixels,
 9350        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9351        target_display_point: DisplayPoint,
 9352        editor_width: Pixels,
 9353        window: &mut Window,
 9354        cx: &mut App,
 9355    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9356        if target_display_point.row().as_f64() < scroll_top {
 9357            let mut element = self
 9358                .render_edit_prediction_line_popover(
 9359                    "Jump to Edit",
 9360                    Some(IconName::ArrowUp),
 9361                    window,
 9362                    cx,
 9363                )
 9364                .into_any();
 9365
 9366            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9367            let offset = point(
 9368                (text_bounds.size.width - size.width) / 2.,
 9369                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9370            );
 9371
 9372            let origin = text_bounds.origin + offset;
 9373            element.prepaint_at(origin, window, cx);
 9374            Some((element, origin))
 9375        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9376            let mut element = self
 9377                .render_edit_prediction_line_popover(
 9378                    "Jump to Edit",
 9379                    Some(IconName::ArrowDown),
 9380                    window,
 9381                    cx,
 9382                )
 9383                .into_any();
 9384
 9385            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9386            let offset = point(
 9387                (text_bounds.size.width - size.width) / 2.,
 9388                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9389            );
 9390
 9391            let origin = text_bounds.origin + offset;
 9392            element.prepaint_at(origin, window, cx);
 9393            Some((element, origin))
 9394        } else {
 9395            self.render_edit_prediction_end_of_line_popover(
 9396                "Jump to Edit",
 9397                editor_snapshot,
 9398                visible_row_range,
 9399                target_display_point,
 9400                line_height,
 9401                scroll_pixel_position,
 9402                content_origin,
 9403                editor_width,
 9404                window,
 9405                cx,
 9406            )
 9407        }
 9408    }
 9409
 9410    fn render_edit_prediction_end_of_line_popover(
 9411        self: &mut Editor,
 9412        label: &'static str,
 9413        editor_snapshot: &EditorSnapshot,
 9414        visible_row_range: Range<DisplayRow>,
 9415        target_display_point: DisplayPoint,
 9416        line_height: Pixels,
 9417        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9418        content_origin: gpui::Point<Pixels>,
 9419        editor_width: Pixels,
 9420        window: &mut Window,
 9421        cx: &mut App,
 9422    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9423        let target_line_end = DisplayPoint::new(
 9424            target_display_point.row(),
 9425            editor_snapshot.line_len(target_display_point.row()),
 9426        );
 9427
 9428        let mut element = self
 9429            .render_edit_prediction_line_popover(label, None, window, cx)
 9430            .into_any();
 9431
 9432        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9433
 9434        let line_origin =
 9435            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9436
 9437        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9438        let mut origin = start_point
 9439            + line_origin
 9440            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9441        origin.x = origin.x.max(content_origin.x);
 9442
 9443        let max_x = content_origin.x + editor_width - size.width;
 9444
 9445        if origin.x > max_x {
 9446            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9447
 9448            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9449                origin.y += offset;
 9450                IconName::ArrowUp
 9451            } else {
 9452                origin.y -= offset;
 9453                IconName::ArrowDown
 9454            };
 9455
 9456            element = self
 9457                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9458                .into_any();
 9459
 9460            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9461
 9462            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9463        }
 9464
 9465        element.prepaint_at(origin, window, cx);
 9466        Some((element, origin))
 9467    }
 9468
 9469    fn render_edit_prediction_diff_popover(
 9470        self: &Editor,
 9471        text_bounds: &Bounds<Pixels>,
 9472        content_origin: gpui::Point<Pixels>,
 9473        right_margin: Pixels,
 9474        editor_snapshot: &EditorSnapshot,
 9475        visible_row_range: Range<DisplayRow>,
 9476        line_layouts: &[LineWithInvisibles],
 9477        line_height: Pixels,
 9478        scroll_position: gpui::Point<ScrollOffset>,
 9479        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9480        newest_selection_head: Option<DisplayPoint>,
 9481        editor_width: Pixels,
 9482        style: &EditorStyle,
 9483        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9484        edit_preview: &Option<language::EditPreview>,
 9485        snapshot: &language::BufferSnapshot,
 9486        window: &mut Window,
 9487        cx: &mut App,
 9488    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9489        let edit_start = edits
 9490            .first()
 9491            .unwrap()
 9492            .0
 9493            .start
 9494            .to_display_point(editor_snapshot);
 9495        let edit_end = edits
 9496            .last()
 9497            .unwrap()
 9498            .0
 9499            .end
 9500            .to_display_point(editor_snapshot);
 9501
 9502        let is_visible = visible_row_range.contains(&edit_start.row())
 9503            || visible_row_range.contains(&edit_end.row());
 9504        if !is_visible {
 9505            return None;
 9506        }
 9507
 9508        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9509            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9510        } else {
 9511            // Fallback for providers without edit_preview
 9512            crate::edit_prediction_fallback_text(edits, cx)
 9513        };
 9514
 9515        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9516        let line_count = highlighted_edits.text.lines().count();
 9517
 9518        const BORDER_WIDTH: Pixels = px(1.);
 9519
 9520        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9521        let has_keybind = keybind.is_some();
 9522
 9523        let mut element = h_flex()
 9524            .items_start()
 9525            .child(
 9526                h_flex()
 9527                    .bg(cx.theme().colors().editor_background)
 9528                    .border(BORDER_WIDTH)
 9529                    .shadow_xs()
 9530                    .border_color(cx.theme().colors().border)
 9531                    .rounded_l_lg()
 9532                    .when(line_count > 1, |el| el.rounded_br_lg())
 9533                    .pr_1()
 9534                    .child(styled_text),
 9535            )
 9536            .child(
 9537                h_flex()
 9538                    .h(line_height + BORDER_WIDTH * 2.)
 9539                    .px_1p5()
 9540                    .gap_1()
 9541                    // Workaround: For some reason, there's a gap if we don't do this
 9542                    .ml(-BORDER_WIDTH)
 9543                    .shadow(vec![gpui::BoxShadow {
 9544                        color: gpui::black().opacity(0.05),
 9545                        offset: point(px(1.), px(1.)),
 9546                        blur_radius: px(2.),
 9547                        spread_radius: px(0.),
 9548                    }])
 9549                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9550                    .border(BORDER_WIDTH)
 9551                    .border_color(cx.theme().colors().border)
 9552                    .rounded_r_lg()
 9553                    .id("edit_prediction_diff_popover_keybind")
 9554                    .when(!has_keybind, |el| {
 9555                        let status_colors = cx.theme().status();
 9556
 9557                        el.bg(status_colors.error_background)
 9558                            .border_color(status_colors.error.opacity(0.6))
 9559                            .child(Icon::new(IconName::Info).color(Color::Error))
 9560                            .cursor_default()
 9561                            .hoverable_tooltip(move |_window, cx| {
 9562                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9563                            })
 9564                    })
 9565                    .children(keybind),
 9566            )
 9567            .into_any();
 9568
 9569        let longest_row =
 9570            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9571        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9572            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9573        } else {
 9574            layout_line(
 9575                longest_row,
 9576                editor_snapshot,
 9577                style,
 9578                editor_width,
 9579                |_| false,
 9580                window,
 9581                cx,
 9582            )
 9583            .width
 9584        };
 9585
 9586        let viewport_bounds =
 9587            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9588                right: -right_margin,
 9589                ..Default::default()
 9590            });
 9591
 9592        let x_after_longest = Pixels::from(
 9593            ScrollPixelOffset::from(
 9594                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9595            ) - scroll_pixel_position.x,
 9596        );
 9597
 9598        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9599
 9600        // Fully visible if it can be displayed within the window (allow overlapping other
 9601        // panes). However, this is only allowed if the popover starts within text_bounds.
 9602        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9603            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9604
 9605        let mut origin = if can_position_to_the_right {
 9606            point(
 9607                x_after_longest,
 9608                text_bounds.origin.y
 9609                    + Pixels::from(
 9610                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9611                            - scroll_pixel_position.y,
 9612                    ),
 9613            )
 9614        } else {
 9615            let cursor_row = newest_selection_head.map(|head| head.row());
 9616            let above_edit = edit_start
 9617                .row()
 9618                .0
 9619                .checked_sub(line_count as u32)
 9620                .map(DisplayRow);
 9621            let below_edit = Some(edit_end.row() + 1);
 9622            let above_cursor =
 9623                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9624            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9625
 9626            // Place the edit popover adjacent to the edit if there is a location
 9627            // available that is onscreen and does not obscure the cursor. Otherwise,
 9628            // place it adjacent to the cursor.
 9629            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9630                .into_iter()
 9631                .flatten()
 9632                .find(|&start_row| {
 9633                    let end_row = start_row + line_count as u32;
 9634                    visible_row_range.contains(&start_row)
 9635                        && visible_row_range.contains(&end_row)
 9636                        && cursor_row
 9637                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9638                })?;
 9639
 9640            content_origin
 9641                + point(
 9642                    Pixels::from(-scroll_pixel_position.x),
 9643                    Pixels::from(
 9644                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9645                    ),
 9646                )
 9647        };
 9648
 9649        origin.x -= BORDER_WIDTH;
 9650
 9651        window.defer_draw(element, origin, 1);
 9652
 9653        // Do not return an element, since it will already be drawn due to defer_draw.
 9654        None
 9655    }
 9656
 9657    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9658        px(30.)
 9659    }
 9660
 9661    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9662        if self.read_only(cx) {
 9663            cx.theme().players().read_only()
 9664        } else {
 9665            self.style.as_ref().unwrap().local_player
 9666        }
 9667    }
 9668
 9669    fn render_edit_prediction_accept_keybind(
 9670        &self,
 9671        window: &mut Window,
 9672        cx: &mut App,
 9673    ) -> Option<AnyElement> {
 9674        let accept_binding =
 9675            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9676        let accept_keystroke = accept_binding.keystroke()?;
 9677
 9678        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9679
 9680        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9681            Color::Accent
 9682        } else {
 9683            Color::Muted
 9684        };
 9685
 9686        h_flex()
 9687            .px_0p5()
 9688            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9689            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9690            .text_size(TextSize::XSmall.rems(cx))
 9691            .child(h_flex().children(ui::render_modifiers(
 9692                accept_keystroke.modifiers(),
 9693                PlatformStyle::platform(),
 9694                Some(modifiers_color),
 9695                Some(IconSize::XSmall.rems().into()),
 9696                true,
 9697            )))
 9698            .when(is_platform_style_mac, |parent| {
 9699                parent.child(accept_keystroke.key().to_string())
 9700            })
 9701            .when(!is_platform_style_mac, |parent| {
 9702                parent.child(
 9703                    Key::new(
 9704                        util::capitalize(accept_keystroke.key()),
 9705                        Some(Color::Default),
 9706                    )
 9707                    .size(Some(IconSize::XSmall.rems().into())),
 9708                )
 9709            })
 9710            .into_any()
 9711            .into()
 9712    }
 9713
 9714    fn render_edit_prediction_line_popover(
 9715        &self,
 9716        label: impl Into<SharedString>,
 9717        icon: Option<IconName>,
 9718        window: &mut Window,
 9719        cx: &mut App,
 9720    ) -> Stateful<Div> {
 9721        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9722
 9723        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9724        let has_keybind = keybind.is_some();
 9725
 9726        h_flex()
 9727            .id("ep-line-popover")
 9728            .py_0p5()
 9729            .pl_1()
 9730            .pr(padding_right)
 9731            .gap_1()
 9732            .rounded_md()
 9733            .border_1()
 9734            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9735            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9736            .shadow_xs()
 9737            .when(!has_keybind, |el| {
 9738                let status_colors = cx.theme().status();
 9739
 9740                el.bg(status_colors.error_background)
 9741                    .border_color(status_colors.error.opacity(0.6))
 9742                    .pl_2()
 9743                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9744                    .cursor_default()
 9745                    .hoverable_tooltip(move |_window, cx| {
 9746                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9747                    })
 9748            })
 9749            .children(keybind)
 9750            .child(
 9751                Label::new(label)
 9752                    .size(LabelSize::Small)
 9753                    .when(!has_keybind, |el| {
 9754                        el.color(cx.theme().status().error.into()).strikethrough()
 9755                    }),
 9756            )
 9757            .when(!has_keybind, |el| {
 9758                el.child(
 9759                    h_flex().ml_1().child(
 9760                        Icon::new(IconName::Info)
 9761                            .size(IconSize::Small)
 9762                            .color(cx.theme().status().error.into()),
 9763                    ),
 9764                )
 9765            })
 9766            .when_some(icon, |element, icon| {
 9767                element.child(
 9768                    div()
 9769                        .mt(px(1.5))
 9770                        .child(Icon::new(icon).size(IconSize::Small)),
 9771                )
 9772            })
 9773    }
 9774
 9775    fn render_edit_prediction_jump_outside_popover(
 9776        &self,
 9777        snapshot: &BufferSnapshot,
 9778        window: &mut Window,
 9779        cx: &mut App,
 9780    ) -> Stateful<Div> {
 9781        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9782        let has_keybind = keybind.is_some();
 9783
 9784        let file_name = snapshot
 9785            .file()
 9786            .map(|file| SharedString::new(file.file_name(cx)))
 9787            .unwrap_or(SharedString::new_static("untitled"));
 9788
 9789        h_flex()
 9790            .id("ep-jump-outside-popover")
 9791            .py_1()
 9792            .px_2()
 9793            .gap_1()
 9794            .rounded_md()
 9795            .border_1()
 9796            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9797            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9798            .shadow_xs()
 9799            .when(!has_keybind, |el| {
 9800                let status_colors = cx.theme().status();
 9801
 9802                el.bg(status_colors.error_background)
 9803                    .border_color(status_colors.error.opacity(0.6))
 9804                    .pl_2()
 9805                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9806                    .cursor_default()
 9807                    .hoverable_tooltip(move |_window, cx| {
 9808                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9809                    })
 9810            })
 9811            .children(keybind)
 9812            .child(
 9813                Label::new(file_name)
 9814                    .size(LabelSize::Small)
 9815                    .buffer_font(cx)
 9816                    .when(!has_keybind, |el| {
 9817                        el.color(cx.theme().status().error.into()).strikethrough()
 9818                    }),
 9819            )
 9820            .when(!has_keybind, |el| {
 9821                el.child(
 9822                    h_flex().ml_1().child(
 9823                        Icon::new(IconName::Info)
 9824                            .size(IconSize::Small)
 9825                            .color(cx.theme().status().error.into()),
 9826                    ),
 9827                )
 9828            })
 9829            .child(
 9830                div()
 9831                    .mt(px(1.5))
 9832                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9833            )
 9834    }
 9835
 9836    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9837        let accent_color = cx.theme().colors().text_accent;
 9838        let editor_bg_color = cx.theme().colors().editor_background;
 9839        editor_bg_color.blend(accent_color.opacity(0.1))
 9840    }
 9841
 9842    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9843        let accent_color = cx.theme().colors().text_accent;
 9844        let editor_bg_color = cx.theme().colors().editor_background;
 9845        editor_bg_color.blend(accent_color.opacity(0.6))
 9846    }
 9847    fn get_prediction_provider_icon_name(
 9848        provider: &Option<RegisteredEditPredictionDelegate>,
 9849    ) -> IconName {
 9850        match provider {
 9851            Some(provider) => match provider.provider.name() {
 9852                "copilot" => IconName::Copilot,
 9853                "supermaven" => IconName::Supermaven,
 9854                _ => IconName::ZedPredict,
 9855            },
 9856            None => IconName::ZedPredict,
 9857        }
 9858    }
 9859
 9860    fn render_edit_prediction_cursor_popover(
 9861        &self,
 9862        min_width: Pixels,
 9863        max_width: Pixels,
 9864        cursor_point: Point,
 9865        style: &EditorStyle,
 9866        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9867        _window: &Window,
 9868        cx: &mut Context<Editor>,
 9869    ) -> Option<AnyElement> {
 9870        let provider = self.edit_prediction_provider.as_ref()?;
 9871        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9872
 9873        let is_refreshing = provider.provider.is_refreshing(cx);
 9874
 9875        fn pending_completion_container(icon: IconName) -> Div {
 9876            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9877        }
 9878
 9879        let completion = match &self.active_edit_prediction {
 9880            Some(prediction) => {
 9881                if !self.has_visible_completions_menu() {
 9882                    const RADIUS: Pixels = px(6.);
 9883                    const BORDER_WIDTH: Pixels = px(1.);
 9884
 9885                    return Some(
 9886                        h_flex()
 9887                            .elevation_2(cx)
 9888                            .border(BORDER_WIDTH)
 9889                            .border_color(cx.theme().colors().border)
 9890                            .when(accept_keystroke.is_none(), |el| {
 9891                                el.border_color(cx.theme().status().error)
 9892                            })
 9893                            .rounded(RADIUS)
 9894                            .rounded_tl(px(0.))
 9895                            .overflow_hidden()
 9896                            .child(div().px_1p5().child(match &prediction.completion {
 9897                                EditPrediction::MoveWithin { target, snapshot } => {
 9898                                    use text::ToPoint as _;
 9899                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9900                                    {
 9901                                        Icon::new(IconName::ZedPredictDown)
 9902                                    } else {
 9903                                        Icon::new(IconName::ZedPredictUp)
 9904                                    }
 9905                                }
 9906                                EditPrediction::MoveOutside { .. } => {
 9907                                    // TODO [zeta2] custom icon for external jump?
 9908                                    Icon::new(provider_icon)
 9909                                }
 9910                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9911                            }))
 9912                            .child(
 9913                                h_flex()
 9914                                    .gap_1()
 9915                                    .py_1()
 9916                                    .px_2()
 9917                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9918                                    .border_l_1()
 9919                                    .border_color(cx.theme().colors().border)
 9920                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9921                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9922                                        el.child(
 9923                                            Label::new("Hold")
 9924                                                .size(LabelSize::Small)
 9925                                                .when(accept_keystroke.is_none(), |el| {
 9926                                                    el.strikethrough()
 9927                                                })
 9928                                                .line_height_style(LineHeightStyle::UiLabel),
 9929                                        )
 9930                                    })
 9931                                    .id("edit_prediction_cursor_popover_keybind")
 9932                                    .when(accept_keystroke.is_none(), |el| {
 9933                                        let status_colors = cx.theme().status();
 9934
 9935                                        el.bg(status_colors.error_background)
 9936                                            .border_color(status_colors.error.opacity(0.6))
 9937                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9938                                            .cursor_default()
 9939                                            .hoverable_tooltip(move |_window, cx| {
 9940                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9941                                                    .into()
 9942                                            })
 9943                                    })
 9944                                    .when_some(
 9945                                        accept_keystroke.as_ref(),
 9946                                        |el, accept_keystroke| {
 9947                                            el.child(h_flex().children(ui::render_modifiers(
 9948                                                accept_keystroke.modifiers(),
 9949                                                PlatformStyle::platform(),
 9950                                                Some(Color::Default),
 9951                                                Some(IconSize::XSmall.rems().into()),
 9952                                                false,
 9953                                            )))
 9954                                        },
 9955                                    ),
 9956                            )
 9957                            .into_any(),
 9958                    );
 9959                }
 9960
 9961                self.render_edit_prediction_cursor_popover_preview(
 9962                    prediction,
 9963                    cursor_point,
 9964                    style,
 9965                    cx,
 9966                )?
 9967            }
 9968
 9969            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9970                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9971                    stale_completion,
 9972                    cursor_point,
 9973                    style,
 9974                    cx,
 9975                )?,
 9976
 9977                None => pending_completion_container(provider_icon)
 9978                    .child(Label::new("...").size(LabelSize::Small)),
 9979            },
 9980
 9981            None => pending_completion_container(provider_icon)
 9982                .child(Label::new("...").size(LabelSize::Small)),
 9983        };
 9984
 9985        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9986            completion
 9987                .with_animation(
 9988                    "loading-completion",
 9989                    Animation::new(Duration::from_secs(2))
 9990                        .repeat()
 9991                        .with_easing(pulsating_between(0.4, 0.8)),
 9992                    |label, delta| label.opacity(delta),
 9993                )
 9994                .into_any_element()
 9995        } else {
 9996            completion.into_any_element()
 9997        };
 9998
 9999        let has_completion = self.active_edit_prediction.is_some();
10000
10001        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
10002        Some(
10003            h_flex()
10004                .min_w(min_width)
10005                .max_w(max_width)
10006                .flex_1()
10007                .elevation_2(cx)
10008                .border_color(cx.theme().colors().border)
10009                .child(
10010                    div()
10011                        .flex_1()
10012                        .py_1()
10013                        .px_2()
10014                        .overflow_hidden()
10015                        .child(completion),
10016                )
10017                .when_some(accept_keystroke, |el, accept_keystroke| {
10018                    if !accept_keystroke.modifiers().modified() {
10019                        return el;
10020                    }
10021
10022                    el.child(
10023                        h_flex()
10024                            .h_full()
10025                            .border_l_1()
10026                            .rounded_r_lg()
10027                            .border_color(cx.theme().colors().border)
10028                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10029                            .gap_1()
10030                            .py_1()
10031                            .px_2()
10032                            .child(
10033                                h_flex()
10034                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10035                                    .when(is_platform_style_mac, |parent| parent.gap_1())
10036                                    .child(h_flex().children(ui::render_modifiers(
10037                                        accept_keystroke.modifiers(),
10038                                        PlatformStyle::platform(),
10039                                        Some(if !has_completion {
10040                                            Color::Muted
10041                                        } else {
10042                                            Color::Default
10043                                        }),
10044                                        None,
10045                                        false,
10046                                    ))),
10047                            )
10048                            .child(Label::new("Preview").into_any_element())
10049                            .opacity(if has_completion { 1.0 } else { 0.4 }),
10050                    )
10051                })
10052                .into_any(),
10053        )
10054    }
10055
10056    fn render_edit_prediction_cursor_popover_preview(
10057        &self,
10058        completion: &EditPredictionState,
10059        cursor_point: Point,
10060        style: &EditorStyle,
10061        cx: &mut Context<Editor>,
10062    ) -> Option<Div> {
10063        use text::ToPoint as _;
10064
10065        fn render_relative_row_jump(
10066            prefix: impl Into<String>,
10067            current_row: u32,
10068            target_row: u32,
10069        ) -> Div {
10070            let (row_diff, arrow) = if target_row < current_row {
10071                (current_row - target_row, IconName::ArrowUp)
10072            } else {
10073                (target_row - current_row, IconName::ArrowDown)
10074            };
10075
10076            h_flex()
10077                .child(
10078                    Label::new(format!("{}{}", prefix.into(), row_diff))
10079                        .color(Color::Muted)
10080                        .size(LabelSize::Small),
10081                )
10082                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
10083        }
10084
10085        let supports_jump = self
10086            .edit_prediction_provider
10087            .as_ref()
10088            .map(|provider| provider.provider.supports_jump_to_edit())
10089            .unwrap_or(true);
10090
10091        match &completion.completion {
10092            EditPrediction::MoveWithin {
10093                target, snapshot, ..
10094            } => {
10095                if !supports_jump {
10096                    return None;
10097                }
10098
10099                Some(
10100                    h_flex()
10101                        .px_2()
10102                        .gap_2()
10103                        .flex_1()
10104                        .child(
10105                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
10106                                Icon::new(IconName::ZedPredictDown)
10107                            } else {
10108                                Icon::new(IconName::ZedPredictUp)
10109                            },
10110                        )
10111                        .child(Label::new("Jump to Edit")),
10112                )
10113            }
10114            EditPrediction::MoveOutside { snapshot, .. } => {
10115                let file_name = snapshot
10116                    .file()
10117                    .map(|file| file.file_name(cx))
10118                    .unwrap_or("untitled");
10119                Some(
10120                    h_flex()
10121                        .px_2()
10122                        .gap_2()
10123                        .flex_1()
10124                        .child(Icon::new(IconName::ZedPredict))
10125                        .child(Label::new(format!("Jump to {file_name}"))),
10126                )
10127            }
10128            EditPrediction::Edit {
10129                edits,
10130                edit_preview,
10131                snapshot,
10132                display_mode: _,
10133            } => {
10134                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
10135
10136                let (highlighted_edits, has_more_lines) =
10137                    if let Some(edit_preview) = edit_preview.as_ref() {
10138                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
10139                            .first_line_preview()
10140                    } else {
10141                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10142                    };
10143
10144                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10145                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10146
10147                let preview = h_flex()
10148                    .gap_1()
10149                    .min_w_16()
10150                    .child(styled_text)
10151                    .when(has_more_lines, |parent| parent.child(""));
10152
10153                let left = if supports_jump && first_edit_row != cursor_point.row {
10154                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10155                        .into_any_element()
10156                } else {
10157                    let icon_name =
10158                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
10159                    Icon::new(icon_name).into_any_element()
10160                };
10161
10162                Some(
10163                    h_flex()
10164                        .h_full()
10165                        .flex_1()
10166                        .gap_2()
10167                        .pr_1()
10168                        .overflow_x_hidden()
10169                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10170                        .child(left)
10171                        .child(preview),
10172                )
10173            }
10174        }
10175    }
10176
10177    pub fn render_context_menu(
10178        &mut self,
10179        max_height_in_lines: u32,
10180        window: &mut Window,
10181        cx: &mut Context<Editor>,
10182    ) -> Option<AnyElement> {
10183        let menu = self.context_menu.borrow();
10184        let menu = menu.as_ref()?;
10185        if !menu.visible() {
10186            return None;
10187        };
10188        self.style
10189            .as_ref()
10190            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10191    }
10192
10193    fn render_context_menu_aside(
10194        &mut self,
10195        max_size: Size<Pixels>,
10196        window: &mut Window,
10197        cx: &mut Context<Editor>,
10198    ) -> Option<AnyElement> {
10199        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10200            if menu.visible() {
10201                menu.render_aside(max_size, window, cx)
10202            } else {
10203                None
10204            }
10205        })
10206    }
10207
10208    fn hide_context_menu(
10209        &mut self,
10210        window: &mut Window,
10211        cx: &mut Context<Self>,
10212    ) -> Option<CodeContextMenu> {
10213        cx.notify();
10214        self.completion_tasks.clear();
10215        let context_menu = self.context_menu.borrow_mut().take();
10216        self.stale_edit_prediction_in_menu.take();
10217        self.update_visible_edit_prediction(window, cx);
10218        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10219            && let Some(completion_provider) = &self.completion_provider
10220        {
10221            completion_provider.selection_changed(None, window, cx);
10222        }
10223        context_menu
10224    }
10225
10226    fn show_snippet_choices(
10227        &mut self,
10228        choices: &Vec<String>,
10229        selection: Range<Anchor>,
10230        cx: &mut Context<Self>,
10231    ) {
10232        let Some((_, buffer, _)) = self
10233            .buffer()
10234            .read(cx)
10235            .excerpt_containing(selection.start, cx)
10236        else {
10237            return;
10238        };
10239        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10240        else {
10241            return;
10242        };
10243        if buffer != end_buffer {
10244            log::error!("expected anchor range to have matching buffer IDs");
10245            return;
10246        }
10247
10248        let id = post_inc(&mut self.next_completion_id);
10249        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10250        let mut context_menu = self.context_menu.borrow_mut();
10251        let old_menu = context_menu.take();
10252        *context_menu = Some(CodeContextMenu::Completions(
10253            CompletionsMenu::new_snippet_choices(
10254                id,
10255                true,
10256                choices,
10257                selection,
10258                buffer,
10259                old_menu.map(|menu| menu.primary_scroll_handle()),
10260                snippet_sort_order,
10261            ),
10262        ));
10263    }
10264
10265    pub fn insert_snippet(
10266        &mut self,
10267        insertion_ranges: &[Range<MultiBufferOffset>],
10268        snippet: Snippet,
10269        window: &mut Window,
10270        cx: &mut Context<Self>,
10271    ) -> Result<()> {
10272        struct Tabstop<T> {
10273            is_end_tabstop: bool,
10274            ranges: Vec<Range<T>>,
10275            choices: Option<Vec<String>>,
10276        }
10277
10278        let tabstops = self.buffer.update(cx, |buffer, cx| {
10279            let snippet_text: Arc<str> = snippet.text.clone().into();
10280            let edits = insertion_ranges
10281                .iter()
10282                .cloned()
10283                .map(|range| (range, snippet_text.clone()));
10284            let autoindent_mode = AutoindentMode::Block {
10285                original_indent_columns: Vec::new(),
10286            };
10287            buffer.edit(edits, Some(autoindent_mode), cx);
10288
10289            let snapshot = &*buffer.read(cx);
10290            let snippet = &snippet;
10291            snippet
10292                .tabstops
10293                .iter()
10294                .map(|tabstop| {
10295                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10296                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10297                    });
10298                    let mut tabstop_ranges = tabstop
10299                        .ranges
10300                        .iter()
10301                        .flat_map(|tabstop_range| {
10302                            let mut delta = 0_isize;
10303                            insertion_ranges.iter().map(move |insertion_range| {
10304                                let insertion_start = insertion_range.start + delta;
10305                                delta += snippet.text.len() as isize
10306                                    - (insertion_range.end - insertion_range.start) as isize;
10307
10308                                let start =
10309                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10310                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10311                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10312                            })
10313                        })
10314                        .collect::<Vec<_>>();
10315                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10316
10317                    Tabstop {
10318                        is_end_tabstop,
10319                        ranges: tabstop_ranges,
10320                        choices: tabstop.choices.clone(),
10321                    }
10322                })
10323                .collect::<Vec<_>>()
10324        });
10325        if let Some(tabstop) = tabstops.first() {
10326            self.change_selections(Default::default(), window, cx, |s| {
10327                // Reverse order so that the first range is the newest created selection.
10328                // Completions will use it and autoscroll will prioritize it.
10329                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10330            });
10331
10332            if let Some(choices) = &tabstop.choices
10333                && let Some(selection) = tabstop.ranges.first()
10334            {
10335                self.show_snippet_choices(choices, selection.clone(), cx)
10336            }
10337
10338            // If we're already at the last tabstop and it's at the end of the snippet,
10339            // we're done, we don't need to keep the state around.
10340            if !tabstop.is_end_tabstop {
10341                let choices = tabstops
10342                    .iter()
10343                    .map(|tabstop| tabstop.choices.clone())
10344                    .collect();
10345
10346                let ranges = tabstops
10347                    .into_iter()
10348                    .map(|tabstop| tabstop.ranges)
10349                    .collect::<Vec<_>>();
10350
10351                self.snippet_stack.push(SnippetState {
10352                    active_index: 0,
10353                    ranges,
10354                    choices,
10355                });
10356            }
10357
10358            // Check whether the just-entered snippet ends with an auto-closable bracket.
10359            if self.autoclose_regions.is_empty() {
10360                let snapshot = self.buffer.read(cx).snapshot(cx);
10361                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10362                    let selection_head = selection.head();
10363                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10364                        continue;
10365                    };
10366
10367                    let mut bracket_pair = None;
10368                    let max_lookup_length = scope
10369                        .brackets()
10370                        .map(|(pair, _)| {
10371                            pair.start
10372                                .as_str()
10373                                .chars()
10374                                .count()
10375                                .max(pair.end.as_str().chars().count())
10376                        })
10377                        .max();
10378                    if let Some(max_lookup_length) = max_lookup_length {
10379                        let next_text = snapshot
10380                            .chars_at(selection_head)
10381                            .take(max_lookup_length)
10382                            .collect::<String>();
10383                        let prev_text = snapshot
10384                            .reversed_chars_at(selection_head)
10385                            .take(max_lookup_length)
10386                            .collect::<String>();
10387
10388                        for (pair, enabled) in scope.brackets() {
10389                            if enabled
10390                                && pair.close
10391                                && prev_text.starts_with(pair.start.as_str())
10392                                && next_text.starts_with(pair.end.as_str())
10393                            {
10394                                bracket_pair = Some(pair.clone());
10395                                break;
10396                            }
10397                        }
10398                    }
10399
10400                    if let Some(pair) = bracket_pair {
10401                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10402                        let autoclose_enabled =
10403                            self.use_autoclose && snapshot_settings.use_autoclose;
10404                        if autoclose_enabled {
10405                            let start = snapshot.anchor_after(selection_head);
10406                            let end = snapshot.anchor_after(selection_head);
10407                            self.autoclose_regions.push(AutocloseRegion {
10408                                selection_id: selection.id,
10409                                range: start..end,
10410                                pair,
10411                            });
10412                        }
10413                    }
10414                }
10415            }
10416        }
10417        Ok(())
10418    }
10419
10420    pub fn move_to_next_snippet_tabstop(
10421        &mut self,
10422        window: &mut Window,
10423        cx: &mut Context<Self>,
10424    ) -> bool {
10425        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10426    }
10427
10428    pub fn move_to_prev_snippet_tabstop(
10429        &mut self,
10430        window: &mut Window,
10431        cx: &mut Context<Self>,
10432    ) -> bool {
10433        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10434    }
10435
10436    pub fn move_to_snippet_tabstop(
10437        &mut self,
10438        bias: Bias,
10439        window: &mut Window,
10440        cx: &mut Context<Self>,
10441    ) -> bool {
10442        if let Some(mut snippet) = self.snippet_stack.pop() {
10443            match bias {
10444                Bias::Left => {
10445                    if snippet.active_index > 0 {
10446                        snippet.active_index -= 1;
10447                    } else {
10448                        self.snippet_stack.push(snippet);
10449                        return false;
10450                    }
10451                }
10452                Bias::Right => {
10453                    if snippet.active_index + 1 < snippet.ranges.len() {
10454                        snippet.active_index += 1;
10455                    } else {
10456                        self.snippet_stack.push(snippet);
10457                        return false;
10458                    }
10459                }
10460            }
10461            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10462                self.change_selections(Default::default(), window, cx, |s| {
10463                    // Reverse order so that the first range is the newest created selection.
10464                    // Completions will use it and autoscroll will prioritize it.
10465                    s.select_ranges(current_ranges.iter().rev().cloned())
10466                });
10467
10468                if let Some(choices) = &snippet.choices[snippet.active_index]
10469                    && let Some(selection) = current_ranges.first()
10470                {
10471                    self.show_snippet_choices(choices, selection.clone(), cx);
10472                }
10473
10474                // If snippet state is not at the last tabstop, push it back on the stack
10475                if snippet.active_index + 1 < snippet.ranges.len() {
10476                    self.snippet_stack.push(snippet);
10477                }
10478                return true;
10479            }
10480        }
10481
10482        false
10483    }
10484
10485    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10486        self.transact(window, cx, |this, window, cx| {
10487            this.select_all(&SelectAll, window, cx);
10488            this.insert("", window, cx);
10489        });
10490    }
10491
10492    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10493        if self.read_only(cx) {
10494            return;
10495        }
10496        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10497        self.transact(window, cx, |this, window, cx| {
10498            this.select_autoclose_pair(window, cx);
10499
10500            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10501
10502            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10503            if !this.linked_edit_ranges.is_empty() {
10504                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10505                let snapshot = this.buffer.read(cx).snapshot(cx);
10506
10507                for selection in selections.iter() {
10508                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10509                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10510                    if selection_start.buffer_id != selection_end.buffer_id {
10511                        continue;
10512                    }
10513                    if let Some(ranges) =
10514                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10515                    {
10516                        for (buffer, entries) in ranges {
10517                            linked_ranges.entry(buffer).or_default().extend(entries);
10518                        }
10519                    }
10520                }
10521            }
10522
10523            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10524            for selection in &mut selections {
10525                if selection.is_empty() {
10526                    let old_head = selection.head();
10527                    let mut new_head =
10528                        movement::left(&display_map, old_head.to_display_point(&display_map))
10529                            .to_point(&display_map);
10530                    if let Some((buffer, line_buffer_range)) = display_map
10531                        .buffer_snapshot()
10532                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10533                    {
10534                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10535                        let indent_len = match indent_size.kind {
10536                            IndentKind::Space => {
10537                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10538                            }
10539                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10540                        };
10541                        if old_head.column <= indent_size.len && old_head.column > 0 {
10542                            let indent_len = indent_len.get();
10543                            new_head = cmp::min(
10544                                new_head,
10545                                MultiBufferPoint::new(
10546                                    old_head.row,
10547                                    ((old_head.column - 1) / indent_len) * indent_len,
10548                                ),
10549                            );
10550                        }
10551                    }
10552
10553                    selection.set_head(new_head, SelectionGoal::None);
10554                }
10555            }
10556
10557            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10558            this.insert("", window, cx);
10559            let empty_str: Arc<str> = Arc::from("");
10560            for (buffer, edits) in linked_ranges {
10561                let snapshot = buffer.read(cx).snapshot();
10562                use text::ToPoint as TP;
10563
10564                let edits = edits
10565                    .into_iter()
10566                    .map(|range| {
10567                        let end_point = TP::to_point(&range.end, &snapshot);
10568                        let mut start_point = TP::to_point(&range.start, &snapshot);
10569
10570                        if end_point == start_point {
10571                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10572                                .saturating_sub(1);
10573                            start_point =
10574                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10575                        };
10576
10577                        (start_point..end_point, empty_str.clone())
10578                    })
10579                    .sorted_by_key(|(range, _)| range.start)
10580                    .collect::<Vec<_>>();
10581                buffer.update(cx, |this, cx| {
10582                    this.edit(edits, None, cx);
10583                })
10584            }
10585            this.refresh_edit_prediction(true, false, window, cx);
10586            refresh_linked_ranges(this, window, cx);
10587        });
10588    }
10589
10590    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10591        if self.read_only(cx) {
10592            return;
10593        }
10594        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10595        self.transact(window, cx, |this, window, cx| {
10596            this.change_selections(Default::default(), window, cx, |s| {
10597                s.move_with(|map, selection| {
10598                    if selection.is_empty() {
10599                        let cursor = movement::right(map, selection.head());
10600                        selection.end = cursor;
10601                        selection.reversed = true;
10602                        selection.goal = SelectionGoal::None;
10603                    }
10604                })
10605            });
10606            this.insert("", window, cx);
10607            this.refresh_edit_prediction(true, false, window, cx);
10608        });
10609    }
10610
10611    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10612        if self.mode.is_single_line() {
10613            cx.propagate();
10614            return;
10615        }
10616
10617        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10618        if self.move_to_prev_snippet_tabstop(window, cx) {
10619            return;
10620        }
10621        self.outdent(&Outdent, window, cx);
10622    }
10623
10624    pub fn next_snippet_tabstop(
10625        &mut self,
10626        _: &NextSnippetTabstop,
10627        window: &mut Window,
10628        cx: &mut Context<Self>,
10629    ) {
10630        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10631            cx.propagate();
10632            return;
10633        }
10634
10635        if self.move_to_next_snippet_tabstop(window, cx) {
10636            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10637            return;
10638        }
10639        cx.propagate();
10640    }
10641
10642    pub fn previous_snippet_tabstop(
10643        &mut self,
10644        _: &PreviousSnippetTabstop,
10645        window: &mut Window,
10646        cx: &mut Context<Self>,
10647    ) {
10648        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10649            cx.propagate();
10650            return;
10651        }
10652
10653        if self.move_to_prev_snippet_tabstop(window, cx) {
10654            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10655            return;
10656        }
10657        cx.propagate();
10658    }
10659
10660    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10661        if self.mode.is_single_line() {
10662            cx.propagate();
10663            return;
10664        }
10665
10666        if self.move_to_next_snippet_tabstop(window, cx) {
10667            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10668            return;
10669        }
10670        if self.read_only(cx) {
10671            return;
10672        }
10673        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10674        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10675        let buffer = self.buffer.read(cx);
10676        let snapshot = buffer.snapshot(cx);
10677        let rows_iter = selections.iter().map(|s| s.head().row);
10678        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10679
10680        let has_some_cursor_in_whitespace = selections
10681            .iter()
10682            .filter(|selection| selection.is_empty())
10683            .any(|selection| {
10684                let cursor = selection.head();
10685                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10686                cursor.column < current_indent.len
10687            });
10688
10689        let mut edits = Vec::new();
10690        let mut prev_edited_row = 0;
10691        let mut row_delta = 0;
10692        for selection in &mut selections {
10693            if selection.start.row != prev_edited_row {
10694                row_delta = 0;
10695            }
10696            prev_edited_row = selection.end.row;
10697
10698            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10699            if selection.is_empty() {
10700                let cursor = selection.head();
10701                let settings = buffer.language_settings_at(cursor, cx);
10702                if settings.indent_list_on_tab {
10703                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10704                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10705                            row_delta = Self::indent_selection(
10706                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10707                            );
10708                            continue;
10709                        }
10710                    }
10711                }
10712            }
10713
10714            // If the selection is non-empty, then increase the indentation of the selected lines.
10715            if !selection.is_empty() {
10716                row_delta =
10717                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10718                continue;
10719            }
10720
10721            let cursor = selection.head();
10722            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10723            if let Some(suggested_indent) =
10724                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10725            {
10726                // Don't do anything if already at suggested indent
10727                // and there is any other cursor which is not
10728                if has_some_cursor_in_whitespace
10729                    && cursor.column == current_indent.len
10730                    && current_indent.len == suggested_indent.len
10731                {
10732                    continue;
10733                }
10734
10735                // Adjust line and move cursor to suggested indent
10736                // if cursor is not at suggested indent
10737                if cursor.column < suggested_indent.len
10738                    && cursor.column <= current_indent.len
10739                    && current_indent.len <= suggested_indent.len
10740                {
10741                    selection.start = Point::new(cursor.row, suggested_indent.len);
10742                    selection.end = selection.start;
10743                    if row_delta == 0 {
10744                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10745                            cursor.row,
10746                            current_indent,
10747                            suggested_indent,
10748                        ));
10749                        row_delta = suggested_indent.len - current_indent.len;
10750                    }
10751                    continue;
10752                }
10753
10754                // If current indent is more than suggested indent
10755                // only move cursor to current indent and skip indent
10756                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10757                    selection.start = Point::new(cursor.row, current_indent.len);
10758                    selection.end = selection.start;
10759                    continue;
10760                }
10761            }
10762
10763            // Otherwise, insert a hard or soft tab.
10764            let settings = buffer.language_settings_at(cursor, cx);
10765            let tab_size = if settings.hard_tabs {
10766                IndentSize::tab()
10767            } else {
10768                let tab_size = settings.tab_size.get();
10769                let indent_remainder = snapshot
10770                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10771                    .flat_map(str::chars)
10772                    .fold(row_delta % tab_size, |counter: u32, c| {
10773                        if c == '\t' {
10774                            0
10775                        } else {
10776                            (counter + 1) % tab_size
10777                        }
10778                    });
10779
10780                let chars_to_next_tab_stop = tab_size - indent_remainder;
10781                IndentSize::spaces(chars_to_next_tab_stop)
10782            };
10783            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10784            selection.end = selection.start;
10785            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10786            row_delta += tab_size.len;
10787        }
10788
10789        self.transact(window, cx, |this, window, cx| {
10790            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10791            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10792            this.refresh_edit_prediction(true, false, window, cx);
10793        });
10794    }
10795
10796    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10797        if self.read_only(cx) {
10798            return;
10799        }
10800        if self.mode.is_single_line() {
10801            cx.propagate();
10802            return;
10803        }
10804
10805        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10806        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10807        let mut prev_edited_row = 0;
10808        let mut row_delta = 0;
10809        let mut edits = Vec::new();
10810        let buffer = self.buffer.read(cx);
10811        let snapshot = buffer.snapshot(cx);
10812        for selection in &mut selections {
10813            if selection.start.row != prev_edited_row {
10814                row_delta = 0;
10815            }
10816            prev_edited_row = selection.end.row;
10817
10818            row_delta =
10819                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10820        }
10821
10822        self.transact(window, cx, |this, window, cx| {
10823            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10824            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10825        });
10826    }
10827
10828    fn indent_selection(
10829        buffer: &MultiBuffer,
10830        snapshot: &MultiBufferSnapshot,
10831        selection: &mut Selection<Point>,
10832        edits: &mut Vec<(Range<Point>, String)>,
10833        delta_for_start_row: u32,
10834        cx: &App,
10835    ) -> u32 {
10836        let settings = buffer.language_settings_at(selection.start, cx);
10837        let tab_size = settings.tab_size.get();
10838        let indent_kind = if settings.hard_tabs {
10839            IndentKind::Tab
10840        } else {
10841            IndentKind::Space
10842        };
10843        let mut start_row = selection.start.row;
10844        let mut end_row = selection.end.row + 1;
10845
10846        // If a selection ends at the beginning of a line, don't indent
10847        // that last line.
10848        if selection.end.column == 0 && selection.end.row > selection.start.row {
10849            end_row -= 1;
10850        }
10851
10852        // Avoid re-indenting a row that has already been indented by a
10853        // previous selection, but still update this selection's column
10854        // to reflect that indentation.
10855        if delta_for_start_row > 0 {
10856            start_row += 1;
10857            selection.start.column += delta_for_start_row;
10858            if selection.end.row == selection.start.row {
10859                selection.end.column += delta_for_start_row;
10860            }
10861        }
10862
10863        let mut delta_for_end_row = 0;
10864        let has_multiple_rows = start_row + 1 != end_row;
10865        for row in start_row..end_row {
10866            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10867            let indent_delta = match (current_indent.kind, indent_kind) {
10868                (IndentKind::Space, IndentKind::Space) => {
10869                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10870                    IndentSize::spaces(columns_to_next_tab_stop)
10871                }
10872                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10873                (_, IndentKind::Tab) => IndentSize::tab(),
10874            };
10875
10876            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10877                0
10878            } else {
10879                selection.start.column
10880            };
10881            let row_start = Point::new(row, start);
10882            edits.push((
10883                row_start..row_start,
10884                indent_delta.chars().collect::<String>(),
10885            ));
10886
10887            // Update this selection's endpoints to reflect the indentation.
10888            if row == selection.start.row {
10889                selection.start.column += indent_delta.len;
10890            }
10891            if row == selection.end.row {
10892                selection.end.column += indent_delta.len;
10893                delta_for_end_row = indent_delta.len;
10894            }
10895        }
10896
10897        if selection.start.row == selection.end.row {
10898            delta_for_start_row + delta_for_end_row
10899        } else {
10900            delta_for_end_row
10901        }
10902    }
10903
10904    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10905        if self.read_only(cx) {
10906            return;
10907        }
10908        if self.mode.is_single_line() {
10909            cx.propagate();
10910            return;
10911        }
10912
10913        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10914        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10915        let selections = self.selections.all::<Point>(&display_map);
10916        let mut deletion_ranges = Vec::new();
10917        let mut last_outdent = None;
10918        {
10919            let buffer = self.buffer.read(cx);
10920            let snapshot = buffer.snapshot(cx);
10921            for selection in &selections {
10922                let settings = buffer.language_settings_at(selection.start, cx);
10923                let tab_size = settings.tab_size.get();
10924                let mut rows = selection.spanned_rows(false, &display_map);
10925
10926                // Avoid re-outdenting a row that has already been outdented by a
10927                // previous selection.
10928                if let Some(last_row) = last_outdent
10929                    && last_row == rows.start
10930                {
10931                    rows.start = rows.start.next_row();
10932                }
10933                let has_multiple_rows = rows.len() > 1;
10934                for row in rows.iter_rows() {
10935                    let indent_size = snapshot.indent_size_for_line(row);
10936                    if indent_size.len > 0 {
10937                        let deletion_len = match indent_size.kind {
10938                            IndentKind::Space => {
10939                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10940                                if columns_to_prev_tab_stop == 0 {
10941                                    tab_size
10942                                } else {
10943                                    columns_to_prev_tab_stop
10944                                }
10945                            }
10946                            IndentKind::Tab => 1,
10947                        };
10948                        let start = if has_multiple_rows
10949                            || deletion_len > selection.start.column
10950                            || indent_size.len < selection.start.column
10951                        {
10952                            0
10953                        } else {
10954                            selection.start.column - deletion_len
10955                        };
10956                        deletion_ranges.push(
10957                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10958                        );
10959                        last_outdent = Some(row);
10960                    }
10961                }
10962            }
10963        }
10964
10965        self.transact(window, cx, |this, window, cx| {
10966            this.buffer.update(cx, |buffer, cx| {
10967                let empty_str: Arc<str> = Arc::default();
10968                buffer.edit(
10969                    deletion_ranges
10970                        .into_iter()
10971                        .map(|range| (range, empty_str.clone())),
10972                    None,
10973                    cx,
10974                );
10975            });
10976            let selections = this
10977                .selections
10978                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10979            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10980        });
10981    }
10982
10983    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10984        if self.read_only(cx) {
10985            return;
10986        }
10987        if self.mode.is_single_line() {
10988            cx.propagate();
10989            return;
10990        }
10991
10992        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10993        let selections = self
10994            .selections
10995            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10996            .into_iter()
10997            .map(|s| s.range());
10998
10999        self.transact(window, cx, |this, window, cx| {
11000            this.buffer.update(cx, |buffer, cx| {
11001                buffer.autoindent_ranges(selections, cx);
11002            });
11003            let selections = this
11004                .selections
11005                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11006            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11007        });
11008    }
11009
11010    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
11011        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11012        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11013        let selections = self.selections.all::<Point>(&display_map);
11014
11015        let mut new_cursors = Vec::new();
11016        let mut edit_ranges = Vec::new();
11017        let mut selections = selections.iter().peekable();
11018        while let Some(selection) = selections.next() {
11019            let mut rows = selection.spanned_rows(false, &display_map);
11020
11021            // Accumulate contiguous regions of rows that we want to delete.
11022            while let Some(next_selection) = selections.peek() {
11023                let next_rows = next_selection.spanned_rows(false, &display_map);
11024                if next_rows.start <= rows.end {
11025                    rows.end = next_rows.end;
11026                    selections.next().unwrap();
11027                } else {
11028                    break;
11029                }
11030            }
11031
11032            let buffer = display_map.buffer_snapshot();
11033            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
11034            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
11035                // If there's a line after the range, delete the \n from the end of the row range
11036                (
11037                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
11038                    rows.end,
11039                )
11040            } else {
11041                // If there isn't a line after the range, delete the \n from the line before the
11042                // start of the row range
11043                edit_start = edit_start.saturating_sub_usize(1);
11044                (buffer.len(), rows.start.previous_row())
11045            };
11046
11047            let text_layout_details = self.text_layout_details(window);
11048            let x = display_map.x_for_display_point(
11049                selection.head().to_display_point(&display_map),
11050                &text_layout_details,
11051            );
11052            let row = Point::new(target_row.0, 0)
11053                .to_display_point(&display_map)
11054                .row();
11055            let column = display_map.display_column_for_x(row, x, &text_layout_details);
11056
11057            new_cursors.push((
11058                selection.id,
11059                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
11060                SelectionGoal::None,
11061            ));
11062            edit_ranges.push(edit_start..edit_end);
11063        }
11064
11065        self.transact(window, cx, |this, window, cx| {
11066            let buffer = this.buffer.update(cx, |buffer, cx| {
11067                let empty_str: Arc<str> = Arc::default();
11068                buffer.edit(
11069                    edit_ranges
11070                        .into_iter()
11071                        .map(|range| (range, empty_str.clone())),
11072                    None,
11073                    cx,
11074                );
11075                buffer.snapshot(cx)
11076            });
11077            let new_selections = new_cursors
11078                .into_iter()
11079                .map(|(id, cursor, goal)| {
11080                    let cursor = cursor.to_point(&buffer);
11081                    Selection {
11082                        id,
11083                        start: cursor,
11084                        end: cursor,
11085                        reversed: false,
11086                        goal,
11087                    }
11088                })
11089                .collect();
11090
11091            this.change_selections(Default::default(), window, cx, |s| {
11092                s.select(new_selections);
11093            });
11094        });
11095    }
11096
11097    pub fn join_lines_impl(
11098        &mut self,
11099        insert_whitespace: bool,
11100        window: &mut Window,
11101        cx: &mut Context<Self>,
11102    ) {
11103        if self.read_only(cx) {
11104            return;
11105        }
11106        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
11107        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
11108            let start = MultiBufferRow(selection.start.row);
11109            // Treat single line selections as if they include the next line. Otherwise this action
11110            // would do nothing for single line selections individual cursors.
11111            let end = if selection.start.row == selection.end.row {
11112                MultiBufferRow(selection.start.row + 1)
11113            } else {
11114                MultiBufferRow(selection.end.row)
11115            };
11116
11117            if let Some(last_row_range) = row_ranges.last_mut()
11118                && start <= last_row_range.end
11119            {
11120                last_row_range.end = end;
11121                continue;
11122            }
11123            row_ranges.push(start..end);
11124        }
11125
11126        let snapshot = self.buffer.read(cx).snapshot(cx);
11127        let mut cursor_positions = Vec::new();
11128        for row_range in &row_ranges {
11129            let anchor = snapshot.anchor_before(Point::new(
11130                row_range.end.previous_row().0,
11131                snapshot.line_len(row_range.end.previous_row()),
11132            ));
11133            cursor_positions.push(anchor..anchor);
11134        }
11135
11136        self.transact(window, cx, |this, window, cx| {
11137            for row_range in row_ranges.into_iter().rev() {
11138                for row in row_range.iter_rows().rev() {
11139                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
11140                    let next_line_row = row.next_row();
11141                    let indent = snapshot.indent_size_for_line(next_line_row);
11142                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
11143
11144                    let replace =
11145                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
11146                            " "
11147                        } else {
11148                            ""
11149                        };
11150
11151                    this.buffer.update(cx, |buffer, cx| {
11152                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11153                    });
11154                }
11155            }
11156
11157            this.change_selections(Default::default(), window, cx, |s| {
11158                s.select_anchor_ranges(cursor_positions)
11159            });
11160        });
11161    }
11162
11163    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11164        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11165        self.join_lines_impl(true, window, cx);
11166    }
11167
11168    pub fn sort_lines_case_sensitive(
11169        &mut self,
11170        _: &SortLinesCaseSensitive,
11171        window: &mut Window,
11172        cx: &mut Context<Self>,
11173    ) {
11174        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11175    }
11176
11177    pub fn sort_lines_by_length(
11178        &mut self,
11179        _: &SortLinesByLength,
11180        window: &mut Window,
11181        cx: &mut Context<Self>,
11182    ) {
11183        self.manipulate_immutable_lines(window, cx, |lines| {
11184            lines.sort_by_key(|&line| line.chars().count())
11185        })
11186    }
11187
11188    pub fn sort_lines_case_insensitive(
11189        &mut self,
11190        _: &SortLinesCaseInsensitive,
11191        window: &mut Window,
11192        cx: &mut Context<Self>,
11193    ) {
11194        self.manipulate_immutable_lines(window, cx, |lines| {
11195            lines.sort_by_key(|line| line.to_lowercase())
11196        })
11197    }
11198
11199    pub fn unique_lines_case_insensitive(
11200        &mut self,
11201        _: &UniqueLinesCaseInsensitive,
11202        window: &mut Window,
11203        cx: &mut Context<Self>,
11204    ) {
11205        self.manipulate_immutable_lines(window, cx, |lines| {
11206            let mut seen = HashSet::default();
11207            lines.retain(|line| seen.insert(line.to_lowercase()));
11208        })
11209    }
11210
11211    pub fn unique_lines_case_sensitive(
11212        &mut self,
11213        _: &UniqueLinesCaseSensitive,
11214        window: &mut Window,
11215        cx: &mut Context<Self>,
11216    ) {
11217        self.manipulate_immutable_lines(window, cx, |lines| {
11218            let mut seen = HashSet::default();
11219            lines.retain(|line| seen.insert(*line));
11220        })
11221    }
11222
11223    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11224        let snapshot = self.buffer.read(cx).snapshot(cx);
11225        for selection in self.selections.disjoint_anchors_arc().iter() {
11226            if snapshot
11227                .language_at(selection.start)
11228                .and_then(|lang| lang.config().wrap_characters.as_ref())
11229                .is_some()
11230            {
11231                return true;
11232            }
11233        }
11234        false
11235    }
11236
11237    fn wrap_selections_in_tag(
11238        &mut self,
11239        _: &WrapSelectionsInTag,
11240        window: &mut Window,
11241        cx: &mut Context<Self>,
11242    ) {
11243        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11244
11245        let snapshot = self.buffer.read(cx).snapshot(cx);
11246
11247        let mut edits = Vec::new();
11248        let mut boundaries = Vec::new();
11249
11250        for selection in self
11251            .selections
11252            .all_adjusted(&self.display_snapshot(cx))
11253            .iter()
11254        {
11255            let Some(wrap_config) = snapshot
11256                .language_at(selection.start)
11257                .and_then(|lang| lang.config().wrap_characters.clone())
11258            else {
11259                continue;
11260            };
11261
11262            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11263            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11264
11265            let start_before = snapshot.anchor_before(selection.start);
11266            let end_after = snapshot.anchor_after(selection.end);
11267
11268            edits.push((start_before..start_before, open_tag));
11269            edits.push((end_after..end_after, close_tag));
11270
11271            boundaries.push((
11272                start_before,
11273                end_after,
11274                wrap_config.start_prefix.len(),
11275                wrap_config.end_suffix.len(),
11276            ));
11277        }
11278
11279        if edits.is_empty() {
11280            return;
11281        }
11282
11283        self.transact(window, cx, |this, window, cx| {
11284            let buffer = this.buffer.update(cx, |buffer, cx| {
11285                buffer.edit(edits, None, cx);
11286                buffer.snapshot(cx)
11287            });
11288
11289            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11290            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11291                boundaries.into_iter()
11292            {
11293                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11294                let close_offset = end_after
11295                    .to_offset(&buffer)
11296                    .saturating_sub_usize(end_suffix_len);
11297                new_selections.push(open_offset..open_offset);
11298                new_selections.push(close_offset..close_offset);
11299            }
11300
11301            this.change_selections(Default::default(), window, cx, |s| {
11302                s.select_ranges(new_selections);
11303            });
11304
11305            this.request_autoscroll(Autoscroll::fit(), cx);
11306        });
11307    }
11308
11309    pub fn toggle_read_only(
11310        &mut self,
11311        _: &workspace::ToggleReadOnlyFile,
11312        _: &mut Window,
11313        cx: &mut Context<Self>,
11314    ) {
11315        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11316            buffer.update(cx, |buffer, cx| {
11317                buffer.set_capability(
11318                    match buffer.capability() {
11319                        Capability::ReadWrite => Capability::Read,
11320                        Capability::Read => Capability::ReadWrite,
11321                        Capability::ReadOnly => Capability::ReadOnly,
11322                    },
11323                    cx,
11324                );
11325            })
11326        }
11327    }
11328
11329    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11330        let Some(project) = self.project.clone() else {
11331            return;
11332        };
11333        self.reload(project, window, cx)
11334            .detach_and_notify_err(window, cx);
11335    }
11336
11337    pub fn restore_file(
11338        &mut self,
11339        _: &::git::RestoreFile,
11340        window: &mut Window,
11341        cx: &mut Context<Self>,
11342    ) {
11343        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11344        let mut buffer_ids = HashSet::default();
11345        let snapshot = self.buffer().read(cx).snapshot(cx);
11346        for selection in self
11347            .selections
11348            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11349        {
11350            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11351        }
11352
11353        let buffer = self.buffer().read(cx);
11354        let ranges = buffer_ids
11355            .into_iter()
11356            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11357            .collect::<Vec<_>>();
11358
11359        self.restore_hunks_in_ranges(ranges, window, cx);
11360    }
11361
11362    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11363        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11364        let selections = self
11365            .selections
11366            .all(&self.display_snapshot(cx))
11367            .into_iter()
11368            .map(|s| s.range())
11369            .collect();
11370        self.restore_hunks_in_ranges(selections, window, cx);
11371    }
11372
11373    pub fn restore_hunks_in_ranges(
11374        &mut self,
11375        ranges: Vec<Range<Point>>,
11376        window: &mut Window,
11377        cx: &mut Context<Editor>,
11378    ) {
11379        let mut revert_changes = HashMap::default();
11380        let chunk_by = self
11381            .snapshot(window, cx)
11382            .hunks_for_ranges(ranges)
11383            .into_iter()
11384            .chunk_by(|hunk| hunk.buffer_id);
11385        for (buffer_id, hunks) in &chunk_by {
11386            let hunks = hunks.collect::<Vec<_>>();
11387            for hunk in &hunks {
11388                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11389            }
11390            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11391        }
11392        drop(chunk_by);
11393        if !revert_changes.is_empty() {
11394            self.transact(window, cx, |editor, window, cx| {
11395                editor.restore(revert_changes, window, cx);
11396            });
11397        }
11398    }
11399
11400    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11401        if let Some(status) = self
11402            .addons
11403            .iter()
11404            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11405        {
11406            return Some(status);
11407        }
11408        self.project
11409            .as_ref()?
11410            .read(cx)
11411            .status_for_buffer_id(buffer_id, cx)
11412    }
11413
11414    pub fn open_active_item_in_terminal(
11415        &mut self,
11416        _: &OpenInTerminal,
11417        window: &mut Window,
11418        cx: &mut Context<Self>,
11419    ) {
11420        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11421            let project_path = buffer.read(cx).project_path(cx)?;
11422            let project = self.project()?.read(cx);
11423            let entry = project.entry_for_path(&project_path, cx)?;
11424            let parent = match &entry.canonical_path {
11425                Some(canonical_path) => canonical_path.to_path_buf(),
11426                None => project.absolute_path(&project_path, cx)?,
11427            }
11428            .parent()?
11429            .to_path_buf();
11430            Some(parent)
11431        }) {
11432            window.dispatch_action(
11433                OpenTerminal {
11434                    working_directory,
11435                    local: false,
11436                }
11437                .boxed_clone(),
11438                cx,
11439            );
11440        }
11441    }
11442
11443    fn set_breakpoint_context_menu(
11444        &mut self,
11445        display_row: DisplayRow,
11446        position: Option<Anchor>,
11447        clicked_point: gpui::Point<Pixels>,
11448        window: &mut Window,
11449        cx: &mut Context<Self>,
11450    ) {
11451        let source = self
11452            .buffer
11453            .read(cx)
11454            .snapshot(cx)
11455            .anchor_before(Point::new(display_row.0, 0u32));
11456
11457        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11458
11459        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11460            self,
11461            source,
11462            clicked_point,
11463            context_menu,
11464            window,
11465            cx,
11466        );
11467    }
11468
11469    fn add_edit_breakpoint_block(
11470        &mut self,
11471        anchor: Anchor,
11472        breakpoint: &Breakpoint,
11473        edit_action: BreakpointPromptEditAction,
11474        window: &mut Window,
11475        cx: &mut Context<Self>,
11476    ) {
11477        let weak_editor = cx.weak_entity();
11478        let bp_prompt = cx.new(|cx| {
11479            BreakpointPromptEditor::new(
11480                weak_editor,
11481                anchor,
11482                breakpoint.clone(),
11483                edit_action,
11484                window,
11485                cx,
11486            )
11487        });
11488
11489        let height = bp_prompt.update(cx, |this, cx| {
11490            this.prompt
11491                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11492        });
11493        let cloned_prompt = bp_prompt.clone();
11494        let blocks = vec![BlockProperties {
11495            style: BlockStyle::Sticky,
11496            placement: BlockPlacement::Above(anchor),
11497            height: Some(height),
11498            render: Arc::new(move |cx| {
11499                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11500                cloned_prompt.clone().into_any_element()
11501            }),
11502            priority: 0,
11503        }];
11504
11505        let focus_handle = bp_prompt.focus_handle(cx);
11506        window.focus(&focus_handle, cx);
11507
11508        let block_ids = self.insert_blocks(blocks, None, cx);
11509        bp_prompt.update(cx, |prompt, _| {
11510            prompt.add_block_ids(block_ids);
11511        });
11512    }
11513
11514    pub(crate) fn breakpoint_at_row(
11515        &self,
11516        row: u32,
11517        window: &mut Window,
11518        cx: &mut Context<Self>,
11519    ) -> Option<(Anchor, Breakpoint)> {
11520        let snapshot = self.snapshot(window, cx);
11521        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11522
11523        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11524    }
11525
11526    pub(crate) fn breakpoint_at_anchor(
11527        &self,
11528        breakpoint_position: Anchor,
11529        snapshot: &EditorSnapshot,
11530        cx: &mut Context<Self>,
11531    ) -> Option<(Anchor, Breakpoint)> {
11532        let buffer = self
11533            .buffer
11534            .read(cx)
11535            .buffer_for_anchor(breakpoint_position, cx)?;
11536
11537        let enclosing_excerpt = breakpoint_position.excerpt_id;
11538        let buffer_snapshot = buffer.read(cx).snapshot();
11539
11540        let row = buffer_snapshot
11541            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11542            .row;
11543
11544        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11545        let anchor_end = snapshot
11546            .buffer_snapshot()
11547            .anchor_after(Point::new(row, line_len));
11548
11549        self.breakpoint_store
11550            .as_ref()?
11551            .read_with(cx, |breakpoint_store, cx| {
11552                breakpoint_store
11553                    .breakpoints(
11554                        &buffer,
11555                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11556                        &buffer_snapshot,
11557                        cx,
11558                    )
11559                    .next()
11560                    .and_then(|(bp, _)| {
11561                        let breakpoint_row = buffer_snapshot
11562                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11563                            .row;
11564
11565                        if breakpoint_row == row {
11566                            snapshot
11567                                .buffer_snapshot()
11568                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11569                                .map(|position| (position, bp.bp.clone()))
11570                        } else {
11571                            None
11572                        }
11573                    })
11574            })
11575    }
11576
11577    pub fn edit_log_breakpoint(
11578        &mut self,
11579        _: &EditLogBreakpoint,
11580        window: &mut Window,
11581        cx: &mut Context<Self>,
11582    ) {
11583        if self.breakpoint_store.is_none() {
11584            return;
11585        }
11586
11587        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11588            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11589                message: None,
11590                state: BreakpointState::Enabled,
11591                condition: None,
11592                hit_condition: None,
11593            });
11594
11595            self.add_edit_breakpoint_block(
11596                anchor,
11597                &breakpoint,
11598                BreakpointPromptEditAction::Log,
11599                window,
11600                cx,
11601            );
11602        }
11603    }
11604
11605    fn breakpoints_at_cursors(
11606        &self,
11607        window: &mut Window,
11608        cx: &mut Context<Self>,
11609    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11610        let snapshot = self.snapshot(window, cx);
11611        let cursors = self
11612            .selections
11613            .disjoint_anchors_arc()
11614            .iter()
11615            .map(|selection| {
11616                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11617
11618                let breakpoint_position = self
11619                    .breakpoint_at_row(cursor_position.row, window, cx)
11620                    .map(|bp| bp.0)
11621                    .unwrap_or_else(|| {
11622                        snapshot
11623                            .display_snapshot
11624                            .buffer_snapshot()
11625                            .anchor_after(Point::new(cursor_position.row, 0))
11626                    });
11627
11628                let breakpoint = self
11629                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11630                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11631
11632                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11633            })
11634            // 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.
11635            .collect::<HashMap<Anchor, _>>();
11636
11637        cursors.into_iter().collect()
11638    }
11639
11640    pub fn enable_breakpoint(
11641        &mut self,
11642        _: &crate::actions::EnableBreakpoint,
11643        window: &mut Window,
11644        cx: &mut Context<Self>,
11645    ) {
11646        if self.breakpoint_store.is_none() {
11647            return;
11648        }
11649
11650        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11651            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11652                continue;
11653            };
11654            self.edit_breakpoint_at_anchor(
11655                anchor,
11656                breakpoint,
11657                BreakpointEditAction::InvertState,
11658                cx,
11659            );
11660        }
11661    }
11662
11663    pub fn disable_breakpoint(
11664        &mut self,
11665        _: &crate::actions::DisableBreakpoint,
11666        window: &mut Window,
11667        cx: &mut Context<Self>,
11668    ) {
11669        if self.breakpoint_store.is_none() {
11670            return;
11671        }
11672
11673        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11674            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11675                continue;
11676            };
11677            self.edit_breakpoint_at_anchor(
11678                anchor,
11679                breakpoint,
11680                BreakpointEditAction::InvertState,
11681                cx,
11682            );
11683        }
11684    }
11685
11686    pub fn toggle_breakpoint(
11687        &mut self,
11688        _: &crate::actions::ToggleBreakpoint,
11689        window: &mut Window,
11690        cx: &mut Context<Self>,
11691    ) {
11692        if self.breakpoint_store.is_none() {
11693            return;
11694        }
11695
11696        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11697            if let Some(breakpoint) = breakpoint {
11698                self.edit_breakpoint_at_anchor(
11699                    anchor,
11700                    breakpoint,
11701                    BreakpointEditAction::Toggle,
11702                    cx,
11703                );
11704            } else {
11705                self.edit_breakpoint_at_anchor(
11706                    anchor,
11707                    Breakpoint::new_standard(),
11708                    BreakpointEditAction::Toggle,
11709                    cx,
11710                );
11711            }
11712        }
11713    }
11714
11715    pub fn edit_breakpoint_at_anchor(
11716        &mut self,
11717        breakpoint_position: Anchor,
11718        breakpoint: Breakpoint,
11719        edit_action: BreakpointEditAction,
11720        cx: &mut Context<Self>,
11721    ) {
11722        let Some(breakpoint_store) = &self.breakpoint_store else {
11723            return;
11724        };
11725
11726        let Some(buffer) = self
11727            .buffer
11728            .read(cx)
11729            .buffer_for_anchor(breakpoint_position, cx)
11730        else {
11731            return;
11732        };
11733
11734        breakpoint_store.update(cx, |breakpoint_store, cx| {
11735            breakpoint_store.toggle_breakpoint(
11736                buffer,
11737                BreakpointWithPosition {
11738                    position: breakpoint_position.text_anchor,
11739                    bp: breakpoint,
11740                },
11741                edit_action,
11742                cx,
11743            );
11744        });
11745
11746        cx.notify();
11747    }
11748
11749    #[cfg(any(test, feature = "test-support"))]
11750    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11751        self.breakpoint_store.clone()
11752    }
11753
11754    pub fn prepare_restore_change(
11755        &self,
11756        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11757        hunk: &MultiBufferDiffHunk,
11758        cx: &mut App,
11759    ) -> Option<()> {
11760        if hunk.is_created_file() {
11761            return None;
11762        }
11763        let buffer = self.buffer.read(cx);
11764        let diff = buffer.diff_for(hunk.buffer_id)?;
11765        let buffer = buffer.buffer(hunk.buffer_id)?;
11766        let buffer = buffer.read(cx);
11767        let original_text = diff
11768            .read(cx)
11769            .base_text(cx)
11770            .as_rope()
11771            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11772        let buffer_snapshot = buffer.snapshot();
11773        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11774        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11775            probe
11776                .0
11777                .start
11778                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11779                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11780        }) {
11781            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11782            Some(())
11783        } else {
11784            None
11785        }
11786    }
11787
11788    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11789        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11790    }
11791
11792    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11793        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11794    }
11795
11796    pub fn rotate_selections_forward(
11797        &mut self,
11798        _: &RotateSelectionsForward,
11799        window: &mut Window,
11800        cx: &mut Context<Self>,
11801    ) {
11802        self.rotate_selections(window, cx, false)
11803    }
11804
11805    pub fn rotate_selections_backward(
11806        &mut self,
11807        _: &RotateSelectionsBackward,
11808        window: &mut Window,
11809        cx: &mut Context<Self>,
11810    ) {
11811        self.rotate_selections(window, cx, true)
11812    }
11813
11814    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11816        let display_snapshot = self.display_snapshot(cx);
11817        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11818
11819        if selections.len() < 2 {
11820            return;
11821        }
11822
11823        let (edits, new_selections) = {
11824            let buffer = self.buffer.read(cx).read(cx);
11825            let has_selections = selections.iter().any(|s| !s.is_empty());
11826            if has_selections {
11827                let mut selected_texts: Vec<String> = selections
11828                    .iter()
11829                    .map(|selection| {
11830                        buffer
11831                            .text_for_range(selection.start..selection.end)
11832                            .collect()
11833                    })
11834                    .collect();
11835
11836                if reverse {
11837                    selected_texts.rotate_left(1);
11838                } else {
11839                    selected_texts.rotate_right(1);
11840                }
11841
11842                let mut offset_delta: i64 = 0;
11843                let mut new_selections = Vec::new();
11844                let edits: Vec<_> = selections
11845                    .iter()
11846                    .zip(selected_texts.iter())
11847                    .map(|(selection, new_text)| {
11848                        let old_len = (selection.end.0 - selection.start.0) as i64;
11849                        let new_len = new_text.len() as i64;
11850                        let adjusted_start =
11851                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11852                        let adjusted_end =
11853                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11854
11855                        new_selections.push(Selection {
11856                            id: selection.id,
11857                            start: adjusted_start,
11858                            end: adjusted_end,
11859                            reversed: selection.reversed,
11860                            goal: selection.goal,
11861                        });
11862
11863                        offset_delta += new_len - old_len;
11864                        (selection.start..selection.end, new_text.clone())
11865                    })
11866                    .collect();
11867                (edits, new_selections)
11868            } else {
11869                let mut all_rows: Vec<u32> = selections
11870                    .iter()
11871                    .map(|selection| buffer.offset_to_point(selection.start).row)
11872                    .collect();
11873                all_rows.sort_unstable();
11874                all_rows.dedup();
11875
11876                if all_rows.len() < 2 {
11877                    return;
11878                }
11879
11880                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11881                    .iter()
11882                    .map(|&row| {
11883                        let start = Point::new(row, 0);
11884                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11885                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11886                    })
11887                    .collect();
11888
11889                let mut line_texts: Vec<String> = line_ranges
11890                    .iter()
11891                    .map(|range| buffer.text_for_range(range.clone()).collect())
11892                    .collect();
11893
11894                if reverse {
11895                    line_texts.rotate_left(1);
11896                } else {
11897                    line_texts.rotate_right(1);
11898                }
11899
11900                let edits = line_ranges
11901                    .iter()
11902                    .zip(line_texts.iter())
11903                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11904                    .collect();
11905
11906                let num_rows = all_rows.len();
11907                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11908                    .iter()
11909                    .enumerate()
11910                    .map(|(i, &row)| (row, i))
11911                    .collect();
11912
11913                // Compute new line start offsets after rotation (handles CRLF)
11914                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11915                let first_line_start = line_ranges[0].start.0;
11916                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11917                for text in line_texts.iter().take(num_rows - 1) {
11918                    let prev_start = *new_line_starts.last().unwrap();
11919                    new_line_starts.push(prev_start + text.len() + newline_len);
11920                }
11921
11922                let new_selections = selections
11923                    .iter()
11924                    .map(|selection| {
11925                        let point = buffer.offset_to_point(selection.start);
11926                        let old_index = row_to_index[&point.row];
11927                        let new_index = if reverse {
11928                            (old_index + num_rows - 1) % num_rows
11929                        } else {
11930                            (old_index + 1) % num_rows
11931                        };
11932                        let new_offset =
11933                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11934                        Selection {
11935                            id: selection.id,
11936                            start: new_offset,
11937                            end: new_offset,
11938                            reversed: selection.reversed,
11939                            goal: selection.goal,
11940                        }
11941                    })
11942                    .collect();
11943
11944                (edits, new_selections)
11945            }
11946        };
11947
11948        self.transact(window, cx, |this, window, cx| {
11949            this.buffer.update(cx, |buffer, cx| {
11950                buffer.edit(edits, None, cx);
11951            });
11952            this.change_selections(Default::default(), window, cx, |s| {
11953                s.select(new_selections);
11954            });
11955        });
11956    }
11957
11958    fn manipulate_lines<M>(
11959        &mut self,
11960        window: &mut Window,
11961        cx: &mut Context<Self>,
11962        mut manipulate: M,
11963    ) where
11964        M: FnMut(&str) -> LineManipulationResult,
11965    {
11966        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11967
11968        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11969        let buffer = self.buffer.read(cx).snapshot(cx);
11970
11971        let mut edits = Vec::new();
11972
11973        let selections = self.selections.all::<Point>(&display_map);
11974        let mut selections = selections.iter().peekable();
11975        let mut contiguous_row_selections = Vec::new();
11976        let mut new_selections = Vec::new();
11977        let mut added_lines = 0;
11978        let mut removed_lines = 0;
11979
11980        while let Some(selection) = selections.next() {
11981            let (start_row, end_row) = consume_contiguous_rows(
11982                &mut contiguous_row_selections,
11983                selection,
11984                &display_map,
11985                &mut selections,
11986            );
11987
11988            let start_point = Point::new(start_row.0, 0);
11989            let end_point = Point::new(
11990                end_row.previous_row().0,
11991                buffer.line_len(end_row.previous_row()),
11992            );
11993            let text = buffer
11994                .text_for_range(start_point..end_point)
11995                .collect::<String>();
11996
11997            let LineManipulationResult {
11998                new_text,
11999                line_count_before,
12000                line_count_after,
12001            } = manipulate(&text);
12002
12003            edits.push((start_point..end_point, new_text));
12004
12005            // Selections must change based on added and removed line count
12006            let start_row =
12007                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
12008            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
12009            new_selections.push(Selection {
12010                id: selection.id,
12011                start: start_row,
12012                end: end_row,
12013                goal: SelectionGoal::None,
12014                reversed: selection.reversed,
12015            });
12016
12017            if line_count_after > line_count_before {
12018                added_lines += line_count_after - line_count_before;
12019            } else if line_count_before > line_count_after {
12020                removed_lines += line_count_before - line_count_after;
12021            }
12022        }
12023
12024        self.transact(window, cx, |this, window, cx| {
12025            let buffer = this.buffer.update(cx, |buffer, cx| {
12026                buffer.edit(edits, None, cx);
12027                buffer.snapshot(cx)
12028            });
12029
12030            // Recalculate offsets on newly edited buffer
12031            let new_selections = new_selections
12032                .iter()
12033                .map(|s| {
12034                    let start_point = Point::new(s.start.0, 0);
12035                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
12036                    Selection {
12037                        id: s.id,
12038                        start: buffer.point_to_offset(start_point),
12039                        end: buffer.point_to_offset(end_point),
12040                        goal: s.goal,
12041                        reversed: s.reversed,
12042                    }
12043                })
12044                .collect();
12045
12046            this.change_selections(Default::default(), window, cx, |s| {
12047                s.select(new_selections);
12048            });
12049
12050            this.request_autoscroll(Autoscroll::fit(), cx);
12051        });
12052    }
12053
12054    fn manipulate_immutable_lines<Fn>(
12055        &mut self,
12056        window: &mut Window,
12057        cx: &mut Context<Self>,
12058        mut callback: Fn,
12059    ) where
12060        Fn: FnMut(&mut Vec<&str>),
12061    {
12062        self.manipulate_lines(window, cx, |text| {
12063            let mut lines: Vec<&str> = text.split('\n').collect();
12064            let line_count_before = lines.len();
12065
12066            callback(&mut lines);
12067
12068            LineManipulationResult {
12069                new_text: lines.join("\n"),
12070                line_count_before,
12071                line_count_after: lines.len(),
12072            }
12073        });
12074    }
12075
12076    fn manipulate_mutable_lines<Fn>(
12077        &mut self,
12078        window: &mut Window,
12079        cx: &mut Context<Self>,
12080        mut callback: Fn,
12081    ) where
12082        Fn: FnMut(&mut Vec<Cow<'_, str>>),
12083    {
12084        self.manipulate_lines(window, cx, |text| {
12085            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
12086            let line_count_before = lines.len();
12087
12088            callback(&mut lines);
12089
12090            LineManipulationResult {
12091                new_text: lines.join("\n"),
12092                line_count_before,
12093                line_count_after: lines.len(),
12094            }
12095        });
12096    }
12097
12098    pub fn convert_indentation_to_spaces(
12099        &mut self,
12100        _: &ConvertIndentationToSpaces,
12101        window: &mut Window,
12102        cx: &mut Context<Self>,
12103    ) {
12104        let settings = self.buffer.read(cx).language_settings(cx);
12105        let tab_size = settings.tab_size.get() as usize;
12106
12107        self.manipulate_mutable_lines(window, cx, |lines| {
12108            // Allocates a reasonably sized scratch buffer once for the whole loop
12109            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12110            // Avoids recomputing spaces that could be inserted many times
12111            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12112                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12113                .collect();
12114
12115            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12116                let mut chars = line.as_ref().chars();
12117                let mut col = 0;
12118                let mut changed = false;
12119
12120                for ch in chars.by_ref() {
12121                    match ch {
12122                        ' ' => {
12123                            reindented_line.push(' ');
12124                            col += 1;
12125                        }
12126                        '\t' => {
12127                            // \t are converted to spaces depending on the current column
12128                            let spaces_len = tab_size - (col % tab_size);
12129                            reindented_line.extend(&space_cache[spaces_len - 1]);
12130                            col += spaces_len;
12131                            changed = true;
12132                        }
12133                        _ => {
12134                            // If we dont append before break, the character is consumed
12135                            reindented_line.push(ch);
12136                            break;
12137                        }
12138                    }
12139                }
12140
12141                if !changed {
12142                    reindented_line.clear();
12143                    continue;
12144                }
12145                // Append the rest of the line and replace old reference with new one
12146                reindented_line.extend(chars);
12147                *line = Cow::Owned(reindented_line.clone());
12148                reindented_line.clear();
12149            }
12150        });
12151    }
12152
12153    pub fn convert_indentation_to_tabs(
12154        &mut self,
12155        _: &ConvertIndentationToTabs,
12156        window: &mut Window,
12157        cx: &mut Context<Self>,
12158    ) {
12159        let settings = self.buffer.read(cx).language_settings(cx);
12160        let tab_size = settings.tab_size.get() as usize;
12161
12162        self.manipulate_mutable_lines(window, cx, |lines| {
12163            // Allocates a reasonably sized buffer once for the whole loop
12164            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12165            // Avoids recomputing spaces that could be inserted many times
12166            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12167                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12168                .collect();
12169
12170            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12171                let mut chars = line.chars();
12172                let mut spaces_count = 0;
12173                let mut first_non_indent_char = None;
12174                let mut changed = false;
12175
12176                for ch in chars.by_ref() {
12177                    match ch {
12178                        ' ' => {
12179                            // Keep track of spaces. Append \t when we reach tab_size
12180                            spaces_count += 1;
12181                            changed = true;
12182                            if spaces_count == tab_size {
12183                                reindented_line.push('\t');
12184                                spaces_count = 0;
12185                            }
12186                        }
12187                        '\t' => {
12188                            reindented_line.push('\t');
12189                            spaces_count = 0;
12190                        }
12191                        _ => {
12192                            // Dont append it yet, we might have remaining spaces
12193                            first_non_indent_char = Some(ch);
12194                            break;
12195                        }
12196                    }
12197                }
12198
12199                if !changed {
12200                    reindented_line.clear();
12201                    continue;
12202                }
12203                // Remaining spaces that didn't make a full tab stop
12204                if spaces_count > 0 {
12205                    reindented_line.extend(&space_cache[spaces_count - 1]);
12206                }
12207                // If we consume an extra character that was not indentation, add it back
12208                if let Some(extra_char) = first_non_indent_char {
12209                    reindented_line.push(extra_char);
12210                }
12211                // Append the rest of the line and replace old reference with new one
12212                reindented_line.extend(chars);
12213                *line = Cow::Owned(reindented_line.clone());
12214                reindented_line.clear();
12215            }
12216        });
12217    }
12218
12219    pub fn convert_to_upper_case(
12220        &mut self,
12221        _: &ConvertToUpperCase,
12222        window: &mut Window,
12223        cx: &mut Context<Self>,
12224    ) {
12225        self.manipulate_text(window, cx, |text| text.to_uppercase())
12226    }
12227
12228    pub fn convert_to_lower_case(
12229        &mut self,
12230        _: &ConvertToLowerCase,
12231        window: &mut Window,
12232        cx: &mut Context<Self>,
12233    ) {
12234        self.manipulate_text(window, cx, |text| text.to_lowercase())
12235    }
12236
12237    pub fn convert_to_title_case(
12238        &mut self,
12239        _: &ConvertToTitleCase,
12240        window: &mut Window,
12241        cx: &mut Context<Self>,
12242    ) {
12243        self.manipulate_text(window, cx, |text| {
12244            text.split('\n')
12245                .map(|line| line.to_case(Case::Title))
12246                .join("\n")
12247        })
12248    }
12249
12250    pub fn convert_to_snake_case(
12251        &mut self,
12252        _: &ConvertToSnakeCase,
12253        window: &mut Window,
12254        cx: &mut Context<Self>,
12255    ) {
12256        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
12257    }
12258
12259    pub fn convert_to_kebab_case(
12260        &mut self,
12261        _: &ConvertToKebabCase,
12262        window: &mut Window,
12263        cx: &mut Context<Self>,
12264    ) {
12265        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12266    }
12267
12268    pub fn convert_to_upper_camel_case(
12269        &mut self,
12270        _: &ConvertToUpperCamelCase,
12271        window: &mut Window,
12272        cx: &mut Context<Self>,
12273    ) {
12274        self.manipulate_text(window, cx, |text| {
12275            text.split('\n')
12276                .map(|line| line.to_case(Case::UpperCamel))
12277                .join("\n")
12278        })
12279    }
12280
12281    pub fn convert_to_lower_camel_case(
12282        &mut self,
12283        _: &ConvertToLowerCamelCase,
12284        window: &mut Window,
12285        cx: &mut Context<Self>,
12286    ) {
12287        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12288    }
12289
12290    pub fn convert_to_opposite_case(
12291        &mut self,
12292        _: &ConvertToOppositeCase,
12293        window: &mut Window,
12294        cx: &mut Context<Self>,
12295    ) {
12296        self.manipulate_text(window, cx, |text| {
12297            text.chars()
12298                .fold(String::with_capacity(text.len()), |mut t, c| {
12299                    if c.is_uppercase() {
12300                        t.extend(c.to_lowercase());
12301                    } else {
12302                        t.extend(c.to_uppercase());
12303                    }
12304                    t
12305                })
12306        })
12307    }
12308
12309    pub fn convert_to_sentence_case(
12310        &mut self,
12311        _: &ConvertToSentenceCase,
12312        window: &mut Window,
12313        cx: &mut Context<Self>,
12314    ) {
12315        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12316    }
12317
12318    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12319        self.manipulate_text(window, cx, |text| {
12320            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12321            if has_upper_case_characters {
12322                text.to_lowercase()
12323            } else {
12324                text.to_uppercase()
12325            }
12326        })
12327    }
12328
12329    pub fn convert_to_rot13(
12330        &mut self,
12331        _: &ConvertToRot13,
12332        window: &mut Window,
12333        cx: &mut Context<Self>,
12334    ) {
12335        self.manipulate_text(window, cx, |text| {
12336            text.chars()
12337                .map(|c| match c {
12338                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12339                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12340                    _ => c,
12341                })
12342                .collect()
12343        })
12344    }
12345
12346    pub fn convert_to_rot47(
12347        &mut self,
12348        _: &ConvertToRot47,
12349        window: &mut Window,
12350        cx: &mut Context<Self>,
12351    ) {
12352        self.manipulate_text(window, cx, |text| {
12353            text.chars()
12354                .map(|c| {
12355                    let code_point = c as u32;
12356                    if code_point >= 33 && code_point <= 126 {
12357                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12358                    }
12359                    c
12360                })
12361                .collect()
12362        })
12363    }
12364
12365    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12366    where
12367        Fn: FnMut(&str) -> String,
12368    {
12369        let buffer = self.buffer.read(cx).snapshot(cx);
12370
12371        let mut new_selections = Vec::new();
12372        let mut edits = Vec::new();
12373        let mut selection_adjustment = 0isize;
12374
12375        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12376            let selection_is_empty = selection.is_empty();
12377
12378            let (start, end) = if selection_is_empty {
12379                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12380                (word_range.start, word_range.end)
12381            } else {
12382                (
12383                    buffer.point_to_offset(selection.start),
12384                    buffer.point_to_offset(selection.end),
12385                )
12386            };
12387
12388            let text = buffer.text_for_range(start..end).collect::<String>();
12389            let old_length = text.len() as isize;
12390            let text = callback(&text);
12391
12392            new_selections.push(Selection {
12393                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12394                end: MultiBufferOffset(
12395                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12396                ),
12397                goal: SelectionGoal::None,
12398                id: selection.id,
12399                reversed: selection.reversed,
12400            });
12401
12402            selection_adjustment += old_length - text.len() as isize;
12403
12404            edits.push((start..end, text));
12405        }
12406
12407        self.transact(window, cx, |this, window, cx| {
12408            this.buffer.update(cx, |buffer, cx| {
12409                buffer.edit(edits, None, cx);
12410            });
12411
12412            this.change_selections(Default::default(), window, cx, |s| {
12413                s.select(new_selections);
12414            });
12415
12416            this.request_autoscroll(Autoscroll::fit(), cx);
12417        });
12418    }
12419
12420    pub fn move_selection_on_drop(
12421        &mut self,
12422        selection: &Selection<Anchor>,
12423        target: DisplayPoint,
12424        is_cut: bool,
12425        window: &mut Window,
12426        cx: &mut Context<Self>,
12427    ) {
12428        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12429        let buffer = display_map.buffer_snapshot();
12430        let mut edits = Vec::new();
12431        let insert_point = display_map
12432            .clip_point(target, Bias::Left)
12433            .to_point(&display_map);
12434        let text = buffer
12435            .text_for_range(selection.start..selection.end)
12436            .collect::<String>();
12437        if is_cut {
12438            edits.push(((selection.start..selection.end), String::new()));
12439        }
12440        let insert_anchor = buffer.anchor_before(insert_point);
12441        edits.push(((insert_anchor..insert_anchor), text));
12442        let last_edit_start = insert_anchor.bias_left(buffer);
12443        let last_edit_end = insert_anchor.bias_right(buffer);
12444        self.transact(window, cx, |this, window, cx| {
12445            this.buffer.update(cx, |buffer, cx| {
12446                buffer.edit(edits, None, cx);
12447            });
12448            this.change_selections(Default::default(), window, cx, |s| {
12449                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12450            });
12451        });
12452    }
12453
12454    pub fn clear_selection_drag_state(&mut self) {
12455        self.selection_drag_state = SelectionDragState::None;
12456    }
12457
12458    pub fn duplicate(
12459        &mut self,
12460        upwards: bool,
12461        whole_lines: bool,
12462        window: &mut Window,
12463        cx: &mut Context<Self>,
12464    ) {
12465        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12466
12467        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12468        let buffer = display_map.buffer_snapshot();
12469        let selections = self.selections.all::<Point>(&display_map);
12470
12471        let mut edits = Vec::new();
12472        let mut selections_iter = selections.iter().peekable();
12473        while let Some(selection) = selections_iter.next() {
12474            let mut rows = selection.spanned_rows(false, &display_map);
12475            // duplicate line-wise
12476            if whole_lines || selection.start == selection.end {
12477                // Avoid duplicating the same lines twice.
12478                while let Some(next_selection) = selections_iter.peek() {
12479                    let next_rows = next_selection.spanned_rows(false, &display_map);
12480                    if next_rows.start < rows.end {
12481                        rows.end = next_rows.end;
12482                        selections_iter.next().unwrap();
12483                    } else {
12484                        break;
12485                    }
12486                }
12487
12488                // Copy the text from the selected row region and splice it either at the start
12489                // or end of the region.
12490                let start = Point::new(rows.start.0, 0);
12491                let end = Point::new(
12492                    rows.end.previous_row().0,
12493                    buffer.line_len(rows.end.previous_row()),
12494                );
12495
12496                let mut text = buffer.text_for_range(start..end).collect::<String>();
12497
12498                let insert_location = if upwards {
12499                    // When duplicating upward, we need to insert before the current line.
12500                    // If we're on the last line and it doesn't end with a newline,
12501                    // we need to add a newline before the duplicated content.
12502                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12503                        && buffer.max_point().column > 0
12504                        && !text.ends_with('\n');
12505
12506                    if needs_leading_newline {
12507                        text.insert(0, '\n');
12508                        end
12509                    } else {
12510                        text.push('\n');
12511                        Point::new(rows.start.0, 0)
12512                    }
12513                } else {
12514                    text.push('\n');
12515                    start
12516                };
12517                edits.push((insert_location..insert_location, text));
12518            } else {
12519                // duplicate character-wise
12520                let start = selection.start;
12521                let end = selection.end;
12522                let text = buffer.text_for_range(start..end).collect::<String>();
12523                edits.push((selection.end..selection.end, text));
12524            }
12525        }
12526
12527        self.transact(window, cx, |this, window, cx| {
12528            this.buffer.update(cx, |buffer, cx| {
12529                buffer.edit(edits, None, cx);
12530            });
12531
12532            // When duplicating upward with whole lines, move the cursor to the duplicated line
12533            if upwards && whole_lines {
12534                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12535
12536                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12537                    let mut new_ranges = Vec::new();
12538                    let selections = s.all::<Point>(&display_map);
12539                    let mut selections_iter = selections.iter().peekable();
12540
12541                    while let Some(first_selection) = selections_iter.next() {
12542                        // Group contiguous selections together to find the total row span
12543                        let mut group_selections = vec![first_selection];
12544                        let mut rows = first_selection.spanned_rows(false, &display_map);
12545
12546                        while let Some(next_selection) = selections_iter.peek() {
12547                            let next_rows = next_selection.spanned_rows(false, &display_map);
12548                            if next_rows.start < rows.end {
12549                                rows.end = next_rows.end;
12550                                group_selections.push(selections_iter.next().unwrap());
12551                            } else {
12552                                break;
12553                            }
12554                        }
12555
12556                        let row_count = rows.end.0 - rows.start.0;
12557
12558                        // Move all selections in this group up by the total number of duplicated rows
12559                        for selection in group_selections {
12560                            let new_start = Point::new(
12561                                selection.start.row.saturating_sub(row_count),
12562                                selection.start.column,
12563                            );
12564
12565                            let new_end = Point::new(
12566                                selection.end.row.saturating_sub(row_count),
12567                                selection.end.column,
12568                            );
12569
12570                            new_ranges.push(new_start..new_end);
12571                        }
12572                    }
12573
12574                    s.select_ranges(new_ranges);
12575                });
12576            }
12577
12578            this.request_autoscroll(Autoscroll::fit(), cx);
12579        });
12580    }
12581
12582    pub fn duplicate_line_up(
12583        &mut self,
12584        _: &DuplicateLineUp,
12585        window: &mut Window,
12586        cx: &mut Context<Self>,
12587    ) {
12588        self.duplicate(true, true, window, cx);
12589    }
12590
12591    pub fn duplicate_line_down(
12592        &mut self,
12593        _: &DuplicateLineDown,
12594        window: &mut Window,
12595        cx: &mut Context<Self>,
12596    ) {
12597        self.duplicate(false, true, window, cx);
12598    }
12599
12600    pub fn duplicate_selection(
12601        &mut self,
12602        _: &DuplicateSelection,
12603        window: &mut Window,
12604        cx: &mut Context<Self>,
12605    ) {
12606        self.duplicate(false, false, window, cx);
12607    }
12608
12609    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12610        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12611        if self.mode.is_single_line() {
12612            cx.propagate();
12613            return;
12614        }
12615
12616        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12617        let buffer = self.buffer.read(cx).snapshot(cx);
12618
12619        let mut edits = Vec::new();
12620        let mut unfold_ranges = Vec::new();
12621        let mut refold_creases = Vec::new();
12622
12623        let selections = self.selections.all::<Point>(&display_map);
12624        let mut selections = selections.iter().peekable();
12625        let mut contiguous_row_selections = Vec::new();
12626        let mut new_selections = Vec::new();
12627
12628        while let Some(selection) = selections.next() {
12629            // Find all the selections that span a contiguous row range
12630            let (start_row, end_row) = consume_contiguous_rows(
12631                &mut contiguous_row_selections,
12632                selection,
12633                &display_map,
12634                &mut selections,
12635            );
12636
12637            // Move the text spanned by the row range to be before the line preceding the row range
12638            if start_row.0 > 0 {
12639                let range_to_move = Point::new(
12640                    start_row.previous_row().0,
12641                    buffer.line_len(start_row.previous_row()),
12642                )
12643                    ..Point::new(
12644                        end_row.previous_row().0,
12645                        buffer.line_len(end_row.previous_row()),
12646                    );
12647                let insertion_point = display_map
12648                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12649                    .0;
12650
12651                // Don't move lines across excerpts
12652                if buffer
12653                    .excerpt_containing(insertion_point..range_to_move.end)
12654                    .is_some()
12655                {
12656                    let text = buffer
12657                        .text_for_range(range_to_move.clone())
12658                        .flat_map(|s| s.chars())
12659                        .skip(1)
12660                        .chain(['\n'])
12661                        .collect::<String>();
12662
12663                    edits.push((
12664                        buffer.anchor_after(range_to_move.start)
12665                            ..buffer.anchor_before(range_to_move.end),
12666                        String::new(),
12667                    ));
12668                    let insertion_anchor = buffer.anchor_after(insertion_point);
12669                    edits.push((insertion_anchor..insertion_anchor, text));
12670
12671                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12672
12673                    // Move selections up
12674                    new_selections.extend(contiguous_row_selections.drain(..).map(
12675                        |mut selection| {
12676                            selection.start.row -= row_delta;
12677                            selection.end.row -= row_delta;
12678                            selection
12679                        },
12680                    ));
12681
12682                    // Move folds up
12683                    unfold_ranges.push(range_to_move.clone());
12684                    for fold in display_map.folds_in_range(
12685                        buffer.anchor_before(range_to_move.start)
12686                            ..buffer.anchor_after(range_to_move.end),
12687                    ) {
12688                        let mut start = fold.range.start.to_point(&buffer);
12689                        let mut end = fold.range.end.to_point(&buffer);
12690                        start.row -= row_delta;
12691                        end.row -= row_delta;
12692                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12693                    }
12694                }
12695            }
12696
12697            // If we didn't move line(s), preserve the existing selections
12698            new_selections.append(&mut contiguous_row_selections);
12699        }
12700
12701        self.transact(window, cx, |this, window, cx| {
12702            this.unfold_ranges(&unfold_ranges, true, true, cx);
12703            this.buffer.update(cx, |buffer, cx| {
12704                for (range, text) in edits {
12705                    buffer.edit([(range, text)], None, cx);
12706                }
12707            });
12708            this.fold_creases(refold_creases, true, window, cx);
12709            this.change_selections(Default::default(), window, cx, |s| {
12710                s.select(new_selections);
12711            })
12712        });
12713    }
12714
12715    pub fn move_line_down(
12716        &mut self,
12717        _: &MoveLineDown,
12718        window: &mut Window,
12719        cx: &mut Context<Self>,
12720    ) {
12721        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12722        if self.mode.is_single_line() {
12723            cx.propagate();
12724            return;
12725        }
12726
12727        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12728        let buffer = self.buffer.read(cx).snapshot(cx);
12729
12730        let mut edits = Vec::new();
12731        let mut unfold_ranges = Vec::new();
12732        let mut refold_creases = Vec::new();
12733
12734        let selections = self.selections.all::<Point>(&display_map);
12735        let mut selections = selections.iter().peekable();
12736        let mut contiguous_row_selections = Vec::new();
12737        let mut new_selections = Vec::new();
12738
12739        while let Some(selection) = selections.next() {
12740            // Find all the selections that span a contiguous row range
12741            let (start_row, end_row) = consume_contiguous_rows(
12742                &mut contiguous_row_selections,
12743                selection,
12744                &display_map,
12745                &mut selections,
12746            );
12747
12748            // Move the text spanned by the row range to be after the last line of the row range
12749            if end_row.0 <= buffer.max_point().row {
12750                let range_to_move =
12751                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12752                let insertion_point = display_map
12753                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12754                    .0;
12755
12756                // Don't move lines across excerpt boundaries
12757                if buffer
12758                    .excerpt_containing(range_to_move.start..insertion_point)
12759                    .is_some()
12760                {
12761                    let mut text = String::from("\n");
12762                    text.extend(buffer.text_for_range(range_to_move.clone()));
12763                    text.pop(); // Drop trailing newline
12764                    edits.push((
12765                        buffer.anchor_after(range_to_move.start)
12766                            ..buffer.anchor_before(range_to_move.end),
12767                        String::new(),
12768                    ));
12769                    let insertion_anchor = buffer.anchor_after(insertion_point);
12770                    edits.push((insertion_anchor..insertion_anchor, text));
12771
12772                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12773
12774                    // Move selections down
12775                    new_selections.extend(contiguous_row_selections.drain(..).map(
12776                        |mut selection| {
12777                            selection.start.row += row_delta;
12778                            selection.end.row += row_delta;
12779                            selection
12780                        },
12781                    ));
12782
12783                    // Move folds down
12784                    unfold_ranges.push(range_to_move.clone());
12785                    for fold in display_map.folds_in_range(
12786                        buffer.anchor_before(range_to_move.start)
12787                            ..buffer.anchor_after(range_to_move.end),
12788                    ) {
12789                        let mut start = fold.range.start.to_point(&buffer);
12790                        let mut end = fold.range.end.to_point(&buffer);
12791                        start.row += row_delta;
12792                        end.row += row_delta;
12793                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12794                    }
12795                }
12796            }
12797
12798            // If we didn't move line(s), preserve the existing selections
12799            new_selections.append(&mut contiguous_row_selections);
12800        }
12801
12802        self.transact(window, cx, |this, window, cx| {
12803            this.unfold_ranges(&unfold_ranges, true, true, cx);
12804            this.buffer.update(cx, |buffer, cx| {
12805                for (range, text) in edits {
12806                    buffer.edit([(range, text)], None, cx);
12807                }
12808            });
12809            this.fold_creases(refold_creases, true, window, cx);
12810            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12811        });
12812    }
12813
12814    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12816        let text_layout_details = &self.text_layout_details(window);
12817        self.transact(window, cx, |this, window, cx| {
12818            let edits = this.change_selections(Default::default(), window, cx, |s| {
12819                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12820                s.move_with(|display_map, selection| {
12821                    if !selection.is_empty() {
12822                        return;
12823                    }
12824
12825                    let mut head = selection.head();
12826                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12827                    if head.column() == display_map.line_len(head.row()) {
12828                        transpose_offset = display_map
12829                            .buffer_snapshot()
12830                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12831                    }
12832
12833                    if transpose_offset == MultiBufferOffset(0) {
12834                        return;
12835                    }
12836
12837                    *head.column_mut() += 1;
12838                    head = display_map.clip_point(head, Bias::Right);
12839                    let goal = SelectionGoal::HorizontalPosition(
12840                        display_map
12841                            .x_for_display_point(head, text_layout_details)
12842                            .into(),
12843                    );
12844                    selection.collapse_to(head, goal);
12845
12846                    let transpose_start = display_map
12847                        .buffer_snapshot()
12848                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12849                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12850                        let transpose_end = display_map
12851                            .buffer_snapshot()
12852                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12853                        if let Some(ch) = display_map
12854                            .buffer_snapshot()
12855                            .chars_at(transpose_start)
12856                            .next()
12857                        {
12858                            edits.push((transpose_start..transpose_offset, String::new()));
12859                            edits.push((transpose_end..transpose_end, ch.to_string()));
12860                        }
12861                    }
12862                });
12863                edits
12864            });
12865            this.buffer
12866                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12867            let selections = this
12868                .selections
12869                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12870            this.change_selections(Default::default(), window, cx, |s| {
12871                s.select(selections);
12872            });
12873        });
12874    }
12875
12876    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12877        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12878        if self.mode.is_single_line() {
12879            cx.propagate();
12880            return;
12881        }
12882
12883        self.rewrap_impl(RewrapOptions::default(), cx)
12884    }
12885
12886    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12887        let buffer = self.buffer.read(cx).snapshot(cx);
12888        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12889
12890        #[derive(Clone, Debug, PartialEq)]
12891        enum CommentFormat {
12892            /// single line comment, with prefix for line
12893            Line(String),
12894            /// single line within a block comment, with prefix for line
12895            BlockLine(String),
12896            /// a single line of a block comment that includes the initial delimiter
12897            BlockCommentWithStart(BlockCommentConfig),
12898            /// a single line of a block comment that includes the ending delimiter
12899            BlockCommentWithEnd(BlockCommentConfig),
12900        }
12901
12902        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12903        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12904            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12905                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12906                .peekable();
12907
12908            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12909                row
12910            } else {
12911                return Vec::new();
12912            };
12913
12914            let language_settings = buffer.language_settings_at(selection.head(), cx);
12915            let language_scope = buffer.language_scope_at(selection.head());
12916
12917            let indent_and_prefix_for_row =
12918                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12919                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12920                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12921                        &language_scope
12922                    {
12923                        let indent_end = Point::new(row, indent.len);
12924                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12925                        let line_text_after_indent = buffer
12926                            .text_for_range(indent_end..line_end)
12927                            .collect::<String>();
12928
12929                        let is_within_comment_override = buffer
12930                            .language_scope_at(indent_end)
12931                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12932                        let comment_delimiters = if is_within_comment_override {
12933                            // we are within a comment syntax node, but we don't
12934                            // yet know what kind of comment: block, doc or line
12935                            match (
12936                                language_scope.documentation_comment(),
12937                                language_scope.block_comment(),
12938                            ) {
12939                                (Some(config), _) | (_, Some(config))
12940                                    if buffer.contains_str_at(indent_end, &config.start) =>
12941                                {
12942                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12943                                }
12944                                (Some(config), _) | (_, Some(config))
12945                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12946                                {
12947                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12948                                }
12949                                (Some(config), _) | (_, Some(config))
12950                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12951                                {
12952                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12953                                }
12954                                (_, _) => language_scope
12955                                    .line_comment_prefixes()
12956                                    .iter()
12957                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12958                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12959                            }
12960                        } else {
12961                            // we not in an overridden comment node, but we may
12962                            // be within a non-overridden line comment node
12963                            language_scope
12964                                .line_comment_prefixes()
12965                                .iter()
12966                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12967                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12968                        };
12969
12970                        let rewrap_prefix = language_scope
12971                            .rewrap_prefixes()
12972                            .iter()
12973                            .find_map(|prefix_regex| {
12974                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12975                                    if mat.start() == 0 {
12976                                        Some(mat.as_str().to_string())
12977                                    } else {
12978                                        None
12979                                    }
12980                                })
12981                            })
12982                            .flatten();
12983                        (comment_delimiters, rewrap_prefix)
12984                    } else {
12985                        (None, None)
12986                    };
12987                    (indent, comment_prefix, rewrap_prefix)
12988                };
12989
12990            let mut ranges = Vec::new();
12991            let from_empty_selection = selection.is_empty();
12992
12993            let mut current_range_start = first_row;
12994            let mut prev_row = first_row;
12995            let (
12996                mut current_range_indent,
12997                mut current_range_comment_delimiters,
12998                mut current_range_rewrap_prefix,
12999            ) = indent_and_prefix_for_row(first_row);
13000
13001            for row in non_blank_rows_iter.skip(1) {
13002                let has_paragraph_break = row > prev_row + 1;
13003
13004                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
13005                    indent_and_prefix_for_row(row);
13006
13007                let has_indent_change = row_indent != current_range_indent;
13008                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
13009
13010                let has_boundary_change = has_comment_change
13011                    || row_rewrap_prefix.is_some()
13012                    || (has_indent_change && current_range_comment_delimiters.is_some());
13013
13014                if has_paragraph_break || has_boundary_change {
13015                    ranges.push((
13016                        language_settings.clone(),
13017                        Point::new(current_range_start, 0)
13018                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13019                        current_range_indent,
13020                        current_range_comment_delimiters.clone(),
13021                        current_range_rewrap_prefix.clone(),
13022                        from_empty_selection,
13023                    ));
13024                    current_range_start = row;
13025                    current_range_indent = row_indent;
13026                    current_range_comment_delimiters = row_comment_delimiters;
13027                    current_range_rewrap_prefix = row_rewrap_prefix;
13028                }
13029                prev_row = row;
13030            }
13031
13032            ranges.push((
13033                language_settings.clone(),
13034                Point::new(current_range_start, 0)
13035                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13036                current_range_indent,
13037                current_range_comment_delimiters,
13038                current_range_rewrap_prefix,
13039                from_empty_selection,
13040            ));
13041
13042            ranges
13043        });
13044
13045        let mut edits = Vec::new();
13046        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
13047
13048        for (
13049            language_settings,
13050            wrap_range,
13051            mut indent_size,
13052            comment_prefix,
13053            rewrap_prefix,
13054            from_empty_selection,
13055        ) in wrap_ranges
13056        {
13057            let mut start_row = wrap_range.start.row;
13058            let mut end_row = wrap_range.end.row;
13059
13060            // Skip selections that overlap with a range that has already been rewrapped.
13061            let selection_range = start_row..end_row;
13062            if rewrapped_row_ranges
13063                .iter()
13064                .any(|range| range.overlaps(&selection_range))
13065            {
13066                continue;
13067            }
13068
13069            let tab_size = language_settings.tab_size;
13070
13071            let (line_prefix, inside_comment) = match &comment_prefix {
13072                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13073                    (Some(prefix.as_str()), true)
13074                }
13075                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
13076                    (Some(prefix.as_ref()), true)
13077                }
13078                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13079                    start: _,
13080                    end: _,
13081                    prefix,
13082                    tab_size,
13083                })) => {
13084                    indent_size.len += tab_size;
13085                    (Some(prefix.as_ref()), true)
13086                }
13087                None => (None, false),
13088            };
13089            let indent_prefix = indent_size.chars().collect::<String>();
13090            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13091
13092            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
13093                RewrapBehavior::InComments => inside_comment,
13094                RewrapBehavior::InSelections => !wrap_range.is_empty(),
13095                RewrapBehavior::Anywhere => true,
13096            };
13097
13098            let should_rewrap = options.override_language_settings
13099                || allow_rewrap_based_on_language
13100                || self.hard_wrap.is_some();
13101            if !should_rewrap {
13102                continue;
13103            }
13104
13105            if from_empty_selection {
13106                'expand_upwards: while start_row > 0 {
13107                    let prev_row = start_row - 1;
13108                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
13109                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
13110                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
13111                    {
13112                        start_row = prev_row;
13113                    } else {
13114                        break 'expand_upwards;
13115                    }
13116                }
13117
13118                'expand_downwards: while end_row < buffer.max_point().row {
13119                    let next_row = end_row + 1;
13120                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
13121                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
13122                        && !buffer.is_line_blank(MultiBufferRow(next_row))
13123                    {
13124                        end_row = next_row;
13125                    } else {
13126                        break 'expand_downwards;
13127                    }
13128                }
13129            }
13130
13131            let start = Point::new(start_row, 0);
13132            let start_offset = ToOffset::to_offset(&start, &buffer);
13133            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
13134            let selection_text = buffer.text_for_range(start..end).collect::<String>();
13135            let mut first_line_delimiter = None;
13136            let mut last_line_delimiter = None;
13137            let Some(lines_without_prefixes) = selection_text
13138                .lines()
13139                .enumerate()
13140                .map(|(ix, line)| {
13141                    let line_trimmed = line.trim_start();
13142                    if rewrap_prefix.is_some() && ix > 0 {
13143                        Ok(line_trimmed)
13144                    } else if let Some(
13145                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13146                            start,
13147                            prefix,
13148                            end,
13149                            tab_size,
13150                        })
13151                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13152                            start,
13153                            prefix,
13154                            end,
13155                            tab_size,
13156                        }),
13157                    ) = &comment_prefix
13158                    {
13159                        let line_trimmed = line_trimmed
13160                            .strip_prefix(start.as_ref())
13161                            .map(|s| {
13162                                let mut indent_size = indent_size;
13163                                indent_size.len -= tab_size;
13164                                let indent_prefix: String = indent_size.chars().collect();
13165                                first_line_delimiter = Some((indent_prefix, start));
13166                                s.trim_start()
13167                            })
13168                            .unwrap_or(line_trimmed);
13169                        let line_trimmed = line_trimmed
13170                            .strip_suffix(end.as_ref())
13171                            .map(|s| {
13172                                last_line_delimiter = Some(end);
13173                                s.trim_end()
13174                            })
13175                            .unwrap_or(line_trimmed);
13176                        let line_trimmed = line_trimmed
13177                            .strip_prefix(prefix.as_ref())
13178                            .unwrap_or(line_trimmed);
13179                        Ok(line_trimmed)
13180                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13181                        line_trimmed.strip_prefix(prefix).with_context(|| {
13182                            format!("line did not start with prefix {prefix:?}: {line:?}")
13183                        })
13184                    } else {
13185                        line_trimmed
13186                            .strip_prefix(&line_prefix.trim_start())
13187                            .with_context(|| {
13188                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13189                            })
13190                    }
13191                })
13192                .collect::<Result<Vec<_>, _>>()
13193                .log_err()
13194            else {
13195                continue;
13196            };
13197
13198            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
13199                buffer
13200                    .language_settings_at(Point::new(start_row, 0), cx)
13201                    .preferred_line_length as usize
13202            });
13203
13204            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13205                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13206            } else {
13207                line_prefix.clone()
13208            };
13209
13210            let wrapped_text = {
13211                let mut wrapped_text = wrap_with_prefix(
13212                    line_prefix,
13213                    subsequent_lines_prefix,
13214                    lines_without_prefixes.join("\n"),
13215                    wrap_column,
13216                    tab_size,
13217                    options.preserve_existing_whitespace,
13218                );
13219
13220                if let Some((indent, delimiter)) = first_line_delimiter {
13221                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13222                }
13223                if let Some(last_line) = last_line_delimiter {
13224                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13225                }
13226
13227                wrapped_text
13228            };
13229
13230            // TODO: should always use char-based diff while still supporting cursor behavior that
13231            // matches vim.
13232            let mut diff_options = DiffOptions::default();
13233            if options.override_language_settings {
13234                diff_options.max_word_diff_len = 0;
13235                diff_options.max_word_diff_line_count = 0;
13236            } else {
13237                diff_options.max_word_diff_len = usize::MAX;
13238                diff_options.max_word_diff_line_count = usize::MAX;
13239            }
13240
13241            for (old_range, new_text) in
13242                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13243            {
13244                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13245                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13246                edits.push((edit_start..edit_end, new_text));
13247            }
13248
13249            rewrapped_row_ranges.push(start_row..=end_row);
13250        }
13251
13252        self.buffer
13253            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13254    }
13255
13256    pub fn cut_common(
13257        &mut self,
13258        cut_no_selection_line: bool,
13259        window: &mut Window,
13260        cx: &mut Context<Self>,
13261    ) -> ClipboardItem {
13262        let mut text = String::new();
13263        let buffer = self.buffer.read(cx).snapshot(cx);
13264        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13265        let mut clipboard_selections = Vec::with_capacity(selections.len());
13266        {
13267            let max_point = buffer.max_point();
13268            let mut is_first = true;
13269            let mut prev_selection_was_entire_line = false;
13270            for selection in &mut selections {
13271                let is_entire_line =
13272                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13273                if is_entire_line {
13274                    selection.start = Point::new(selection.start.row, 0);
13275                    if !selection.is_empty() && selection.end.column == 0 {
13276                        selection.end = cmp::min(max_point, selection.end);
13277                    } else {
13278                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13279                    }
13280                    selection.goal = SelectionGoal::None;
13281                }
13282                if is_first {
13283                    is_first = false;
13284                } else if !prev_selection_was_entire_line {
13285                    text += "\n";
13286                }
13287                prev_selection_was_entire_line = is_entire_line;
13288                let mut len = 0;
13289                for chunk in buffer.text_for_range(selection.start..selection.end) {
13290                    text.push_str(chunk);
13291                    len += chunk.len();
13292                }
13293
13294                clipboard_selections.push(ClipboardSelection::for_buffer(
13295                    len,
13296                    is_entire_line,
13297                    selection.range(),
13298                    &buffer,
13299                    self.project.as_ref(),
13300                    cx,
13301                ));
13302            }
13303        }
13304
13305        self.transact(window, cx, |this, window, cx| {
13306            this.change_selections(Default::default(), window, cx, |s| {
13307                s.select(selections);
13308            });
13309            this.insert("", window, cx);
13310        });
13311        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13312    }
13313
13314    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13315        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13316        let item = self.cut_common(true, window, cx);
13317        cx.write_to_clipboard(item);
13318    }
13319
13320    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13321        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13322        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13323            s.move_with(|snapshot, sel| {
13324                if sel.is_empty() {
13325                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13326                }
13327                if sel.is_empty() {
13328                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13329                }
13330            });
13331        });
13332        let item = self.cut_common(false, window, cx);
13333        cx.set_global(KillRing(item))
13334    }
13335
13336    pub fn kill_ring_yank(
13337        &mut self,
13338        _: &KillRingYank,
13339        window: &mut Window,
13340        cx: &mut Context<Self>,
13341    ) {
13342        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13343        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13344            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13345                (kill_ring.text().to_string(), kill_ring.metadata_json())
13346            } else {
13347                return;
13348            }
13349        } else {
13350            return;
13351        };
13352        self.do_paste(&text, metadata, false, window, cx);
13353    }
13354
13355    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13356        self.do_copy(true, cx);
13357    }
13358
13359    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13360        self.do_copy(false, cx);
13361    }
13362
13363    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13364        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13365        let buffer = self.buffer.read(cx).read(cx);
13366        let mut text = String::new();
13367
13368        let mut clipboard_selections = Vec::with_capacity(selections.len());
13369        {
13370            let max_point = buffer.max_point();
13371            let mut is_first = true;
13372            let mut prev_selection_was_entire_line = false;
13373            for selection in &selections {
13374                let mut start = selection.start;
13375                let mut end = selection.end;
13376                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13377                let mut add_trailing_newline = false;
13378                if is_entire_line {
13379                    start = Point::new(start.row, 0);
13380                    let next_line_start = Point::new(end.row + 1, 0);
13381                    if next_line_start <= max_point {
13382                        end = next_line_start;
13383                    } else {
13384                        // We're on the last line without a trailing newline.
13385                        // Copy to the end of the line and add a newline afterwards.
13386                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13387                        add_trailing_newline = true;
13388                    }
13389                }
13390
13391                let mut trimmed_selections = Vec::new();
13392                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13393                    let row = MultiBufferRow(start.row);
13394                    let first_indent = buffer.indent_size_for_line(row);
13395                    if first_indent.len == 0 || start.column > first_indent.len {
13396                        trimmed_selections.push(start..end);
13397                    } else {
13398                        trimmed_selections.push(
13399                            Point::new(row.0, first_indent.len)
13400                                ..Point::new(row.0, buffer.line_len(row)),
13401                        );
13402                        for row in start.row + 1..=end.row {
13403                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13404                            if row == end.row {
13405                                line_len = end.column;
13406                            }
13407                            if line_len == 0 {
13408                                trimmed_selections
13409                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13410                                continue;
13411                            }
13412                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13413                            if row_indent_size.len >= first_indent.len {
13414                                trimmed_selections.push(
13415                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13416                                );
13417                            } else {
13418                                trimmed_selections.clear();
13419                                trimmed_selections.push(start..end);
13420                                break;
13421                            }
13422                        }
13423                    }
13424                } else {
13425                    trimmed_selections.push(start..end);
13426                }
13427
13428                let is_multiline_trim = trimmed_selections.len() > 1;
13429                for trimmed_range in trimmed_selections {
13430                    if is_first {
13431                        is_first = false;
13432                    } else if is_multiline_trim || !prev_selection_was_entire_line {
13433                        text += "\n";
13434                    }
13435                    prev_selection_was_entire_line = is_entire_line && !is_multiline_trim;
13436                    let mut len = 0;
13437                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13438                        text.push_str(chunk);
13439                        len += chunk.len();
13440                    }
13441                    if add_trailing_newline {
13442                        text.push('\n');
13443                        len += 1;
13444                    }
13445                    clipboard_selections.push(ClipboardSelection::for_buffer(
13446                        len,
13447                        is_entire_line,
13448                        trimmed_range,
13449                        &buffer,
13450                        self.project.as_ref(),
13451                        cx,
13452                    ));
13453                }
13454            }
13455        }
13456
13457        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13458            text,
13459            clipboard_selections,
13460        ));
13461    }
13462
13463    pub fn do_paste(
13464        &mut self,
13465        text: &String,
13466        clipboard_selections: Option<Vec<ClipboardSelection>>,
13467        handle_entire_lines: bool,
13468        window: &mut Window,
13469        cx: &mut Context<Self>,
13470    ) {
13471        if self.read_only(cx) {
13472            return;
13473        }
13474
13475        let clipboard_text = Cow::Borrowed(text.as_str());
13476
13477        self.transact(window, cx, |this, window, cx| {
13478            let had_active_edit_prediction = this.has_active_edit_prediction();
13479            let display_map = this.display_snapshot(cx);
13480            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13481            let cursor_offset = this
13482                .selections
13483                .last::<MultiBufferOffset>(&display_map)
13484                .head();
13485
13486            if let Some(mut clipboard_selections) = clipboard_selections {
13487                let all_selections_were_entire_line =
13488                    clipboard_selections.iter().all(|s| s.is_entire_line);
13489                let first_selection_indent_column =
13490                    clipboard_selections.first().map(|s| s.first_line_indent);
13491                if clipboard_selections.len() != old_selections.len() {
13492                    clipboard_selections.drain(..);
13493                }
13494                let mut auto_indent_on_paste = true;
13495
13496                this.buffer.update(cx, |buffer, cx| {
13497                    let snapshot = buffer.read(cx);
13498                    auto_indent_on_paste = snapshot
13499                        .language_settings_at(cursor_offset, cx)
13500                        .auto_indent_on_paste;
13501
13502                    let mut start_offset = 0;
13503                    let mut edits = Vec::new();
13504                    let mut original_indent_columns = Vec::new();
13505                    for (ix, selection) in old_selections.iter().enumerate() {
13506                        let to_insert;
13507                        let entire_line;
13508                        let original_indent_column;
13509                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13510                            let end_offset = start_offset + clipboard_selection.len;
13511                            to_insert = &clipboard_text[start_offset..end_offset];
13512                            entire_line = clipboard_selection.is_entire_line;
13513                            start_offset = if entire_line {
13514                                end_offset
13515                            } else {
13516                                end_offset + 1
13517                            };
13518                            original_indent_column = Some(clipboard_selection.first_line_indent);
13519                        } else {
13520                            to_insert = &*clipboard_text;
13521                            entire_line = all_selections_were_entire_line;
13522                            original_indent_column = first_selection_indent_column
13523                        }
13524
13525                        let (range, to_insert) =
13526                            if selection.is_empty() && handle_entire_lines && entire_line {
13527                                // If the corresponding selection was empty when this slice of the
13528                                // clipboard text was written, then the entire line containing the
13529                                // selection was copied. If this selection is also currently empty,
13530                                // then paste the line before the current line of the buffer.
13531                                let column = selection.start.to_point(&snapshot).column as usize;
13532                                let line_start = selection.start - column;
13533                                (line_start..line_start, Cow::Borrowed(to_insert))
13534                            } else {
13535                                let language = snapshot.language_at(selection.head());
13536                                let range = selection.range();
13537                                if let Some(language) = language
13538                                    && language.name() == "Markdown".into()
13539                                {
13540                                    edit_for_markdown_paste(
13541                                        &snapshot,
13542                                        range,
13543                                        to_insert,
13544                                        url::Url::parse(to_insert).ok(),
13545                                    )
13546                                } else {
13547                                    (range, Cow::Borrowed(to_insert))
13548                                }
13549                            };
13550
13551                        edits.push((range, to_insert));
13552                        original_indent_columns.push(original_indent_column);
13553                    }
13554                    drop(snapshot);
13555
13556                    buffer.edit(
13557                        edits,
13558                        if auto_indent_on_paste {
13559                            Some(AutoindentMode::Block {
13560                                original_indent_columns,
13561                            })
13562                        } else {
13563                            None
13564                        },
13565                        cx,
13566                    );
13567                });
13568
13569                let selections = this
13570                    .selections
13571                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13572                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13573            } else {
13574                let url = url::Url::parse(&clipboard_text).ok();
13575
13576                let auto_indent_mode = if !clipboard_text.is_empty() {
13577                    Some(AutoindentMode::Block {
13578                        original_indent_columns: Vec::new(),
13579                    })
13580                } else {
13581                    None
13582                };
13583
13584                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13585                    let snapshot = buffer.snapshot(cx);
13586
13587                    let anchors = old_selections
13588                        .iter()
13589                        .map(|s| {
13590                            let anchor = snapshot.anchor_after(s.head());
13591                            s.map(|_| anchor)
13592                        })
13593                        .collect::<Vec<_>>();
13594
13595                    let mut edits = Vec::new();
13596
13597                    for selection in old_selections.iter() {
13598                        let language = snapshot.language_at(selection.head());
13599                        let range = selection.range();
13600
13601                        let (edit_range, edit_text) = if let Some(language) = language
13602                            && language.name() == "Markdown".into()
13603                        {
13604                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13605                        } else {
13606                            (range, clipboard_text.clone())
13607                        };
13608
13609                        edits.push((edit_range, edit_text));
13610                    }
13611
13612                    drop(snapshot);
13613                    buffer.edit(edits, auto_indent_mode, cx);
13614
13615                    anchors
13616                });
13617
13618                this.change_selections(Default::default(), window, cx, |s| {
13619                    s.select_anchors(selection_anchors);
13620                });
13621            }
13622
13623            //   🤔                 |    ..     | show_in_menu |
13624            // | ..                  |   true        true
13625            // | had_edit_prediction |   false       true
13626
13627            let trigger_in_words =
13628                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13629
13630            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13631        });
13632    }
13633
13634    pub fn diff_clipboard_with_selection(
13635        &mut self,
13636        _: &DiffClipboardWithSelection,
13637        window: &mut Window,
13638        cx: &mut Context<Self>,
13639    ) {
13640        let selections = self
13641            .selections
13642            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13643
13644        if selections.is_empty() {
13645            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13646            return;
13647        };
13648
13649        let clipboard_text = match cx.read_from_clipboard() {
13650            Some(item) => match item.entries().first() {
13651                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13652                _ => None,
13653            },
13654            None => None,
13655        };
13656
13657        let Some(clipboard_text) = clipboard_text else {
13658            log::warn!("Clipboard doesn't contain text.");
13659            return;
13660        };
13661
13662        window.dispatch_action(
13663            Box::new(DiffClipboardWithSelectionData {
13664                clipboard_text,
13665                editor: cx.entity(),
13666            }),
13667            cx,
13668        );
13669    }
13670
13671    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13672        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13673        if let Some(item) = cx.read_from_clipboard() {
13674            let entries = item.entries();
13675
13676            match entries.first() {
13677                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13678                // of all the pasted entries.
13679                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13680                    .do_paste(
13681                        clipboard_string.text(),
13682                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13683                        true,
13684                        window,
13685                        cx,
13686                    ),
13687                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13688            }
13689        }
13690    }
13691
13692    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13693        if self.read_only(cx) {
13694            return;
13695        }
13696
13697        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13698
13699        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13700            if let Some((selections, _)) =
13701                self.selection_history.transaction(transaction_id).cloned()
13702            {
13703                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13704                    s.select_anchors(selections.to_vec());
13705                });
13706            } else {
13707                log::error!(
13708                    "No entry in selection_history found for undo. \
13709                     This may correspond to a bug where undo does not update the selection. \
13710                     If this is occurring, please add details to \
13711                     https://github.com/zed-industries/zed/issues/22692"
13712                );
13713            }
13714            self.request_autoscroll(Autoscroll::fit(), cx);
13715            self.unmark_text(window, cx);
13716            self.refresh_edit_prediction(true, false, window, cx);
13717            cx.emit(EditorEvent::Edited { transaction_id });
13718            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13719        }
13720    }
13721
13722    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13723        if self.read_only(cx) {
13724            return;
13725        }
13726
13727        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13728
13729        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13730            if let Some((_, Some(selections))) =
13731                self.selection_history.transaction(transaction_id).cloned()
13732            {
13733                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13734                    s.select_anchors(selections.to_vec());
13735                });
13736            } else {
13737                log::error!(
13738                    "No entry in selection_history found for redo. \
13739                     This may correspond to a bug where undo does not update the selection. \
13740                     If this is occurring, please add details to \
13741                     https://github.com/zed-industries/zed/issues/22692"
13742                );
13743            }
13744            self.request_autoscroll(Autoscroll::fit(), cx);
13745            self.unmark_text(window, cx);
13746            self.refresh_edit_prediction(true, false, window, cx);
13747            cx.emit(EditorEvent::Edited { transaction_id });
13748        }
13749    }
13750
13751    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13752        self.buffer
13753            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13754    }
13755
13756    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13757        self.buffer
13758            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13759    }
13760
13761    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13762        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13763        self.change_selections(Default::default(), window, cx, |s| {
13764            s.move_with(|map, selection| {
13765                let cursor = if selection.is_empty() {
13766                    movement::left(map, selection.start)
13767                } else {
13768                    selection.start
13769                };
13770                selection.collapse_to(cursor, SelectionGoal::None);
13771            });
13772        })
13773    }
13774
13775    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13776        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13777        self.change_selections(Default::default(), window, cx, |s| {
13778            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13779        })
13780    }
13781
13782    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13783        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13784        self.change_selections(Default::default(), window, cx, |s| {
13785            s.move_with(|map, selection| {
13786                let cursor = if selection.is_empty() {
13787                    movement::right(map, selection.end)
13788                } else {
13789                    selection.end
13790                };
13791                selection.collapse_to(cursor, SelectionGoal::None)
13792            });
13793        })
13794    }
13795
13796    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13798        self.change_selections(Default::default(), window, cx, |s| {
13799            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13800        });
13801    }
13802
13803    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13804        if self.take_rename(true, window, cx).is_some() {
13805            return;
13806        }
13807
13808        if self.mode.is_single_line() {
13809            cx.propagate();
13810            return;
13811        }
13812
13813        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13814
13815        let text_layout_details = &self.text_layout_details(window);
13816        let selection_count = self.selections.count();
13817        let first_selection = self.selections.first_anchor();
13818
13819        self.change_selections(Default::default(), window, cx, |s| {
13820            s.move_with(|map, selection| {
13821                if !selection.is_empty() {
13822                    selection.goal = SelectionGoal::None;
13823                }
13824                let (cursor, goal) = movement::up(
13825                    map,
13826                    selection.start,
13827                    selection.goal,
13828                    false,
13829                    text_layout_details,
13830                );
13831                selection.collapse_to(cursor, goal);
13832            });
13833        });
13834
13835        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13836        {
13837            cx.propagate();
13838        }
13839    }
13840
13841    pub fn move_up_by_lines(
13842        &mut self,
13843        action: &MoveUpByLines,
13844        window: &mut Window,
13845        cx: &mut Context<Self>,
13846    ) {
13847        if self.take_rename(true, window, cx).is_some() {
13848            return;
13849        }
13850
13851        if self.mode.is_single_line() {
13852            cx.propagate();
13853            return;
13854        }
13855
13856        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13857
13858        let text_layout_details = &self.text_layout_details(window);
13859
13860        self.change_selections(Default::default(), window, cx, |s| {
13861            s.move_with(|map, selection| {
13862                if !selection.is_empty() {
13863                    selection.goal = SelectionGoal::None;
13864                }
13865                let (cursor, goal) = movement::up_by_rows(
13866                    map,
13867                    selection.start,
13868                    action.lines,
13869                    selection.goal,
13870                    false,
13871                    text_layout_details,
13872                );
13873                selection.collapse_to(cursor, goal);
13874            });
13875        })
13876    }
13877
13878    pub fn move_down_by_lines(
13879        &mut self,
13880        action: &MoveDownByLines,
13881        window: &mut Window,
13882        cx: &mut Context<Self>,
13883    ) {
13884        if self.take_rename(true, window, cx).is_some() {
13885            return;
13886        }
13887
13888        if self.mode.is_single_line() {
13889            cx.propagate();
13890            return;
13891        }
13892
13893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13894
13895        let text_layout_details = &self.text_layout_details(window);
13896
13897        self.change_selections(Default::default(), window, cx, |s| {
13898            s.move_with(|map, selection| {
13899                if !selection.is_empty() {
13900                    selection.goal = SelectionGoal::None;
13901                }
13902                let (cursor, goal) = movement::down_by_rows(
13903                    map,
13904                    selection.start,
13905                    action.lines,
13906                    selection.goal,
13907                    false,
13908                    text_layout_details,
13909                );
13910                selection.collapse_to(cursor, goal);
13911            });
13912        })
13913    }
13914
13915    pub fn select_down_by_lines(
13916        &mut self,
13917        action: &SelectDownByLines,
13918        window: &mut Window,
13919        cx: &mut Context<Self>,
13920    ) {
13921        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13922        let text_layout_details = &self.text_layout_details(window);
13923        self.change_selections(Default::default(), window, cx, |s| {
13924            s.move_heads_with(|map, head, goal| {
13925                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13926            })
13927        })
13928    }
13929
13930    pub fn select_up_by_lines(
13931        &mut self,
13932        action: &SelectUpByLines,
13933        window: &mut Window,
13934        cx: &mut Context<Self>,
13935    ) {
13936        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13937        let text_layout_details = &self.text_layout_details(window);
13938        self.change_selections(Default::default(), window, cx, |s| {
13939            s.move_heads_with(|map, head, goal| {
13940                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13941            })
13942        })
13943    }
13944
13945    pub fn select_page_up(
13946        &mut self,
13947        _: &SelectPageUp,
13948        window: &mut Window,
13949        cx: &mut Context<Self>,
13950    ) {
13951        let Some(row_count) = self.visible_row_count() else {
13952            return;
13953        };
13954
13955        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13956
13957        let text_layout_details = &self.text_layout_details(window);
13958
13959        self.change_selections(Default::default(), window, cx, |s| {
13960            s.move_heads_with(|map, head, goal| {
13961                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13962            })
13963        })
13964    }
13965
13966    pub fn move_page_up(
13967        &mut self,
13968        action: &MovePageUp,
13969        window: &mut Window,
13970        cx: &mut Context<Self>,
13971    ) {
13972        if self.take_rename(true, window, cx).is_some() {
13973            return;
13974        }
13975
13976        if self
13977            .context_menu
13978            .borrow_mut()
13979            .as_mut()
13980            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13981            .unwrap_or(false)
13982        {
13983            return;
13984        }
13985
13986        if matches!(self.mode, EditorMode::SingleLine) {
13987            cx.propagate();
13988            return;
13989        }
13990
13991        let Some(row_count) = self.visible_row_count() else {
13992            return;
13993        };
13994
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13996
13997        let effects = if action.center_cursor {
13998            SelectionEffects::scroll(Autoscroll::center())
13999        } else {
14000            SelectionEffects::default()
14001        };
14002
14003        let text_layout_details = &self.text_layout_details(window);
14004
14005        self.change_selections(effects, window, cx, |s| {
14006            s.move_with(|map, selection| {
14007                if !selection.is_empty() {
14008                    selection.goal = SelectionGoal::None;
14009                }
14010                let (cursor, goal) = movement::up_by_rows(
14011                    map,
14012                    selection.end,
14013                    row_count,
14014                    selection.goal,
14015                    false,
14016                    text_layout_details,
14017                );
14018                selection.collapse_to(cursor, goal);
14019            });
14020        });
14021    }
14022
14023    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
14024        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14025        let text_layout_details = &self.text_layout_details(window);
14026        self.change_selections(Default::default(), window, cx, |s| {
14027            s.move_heads_with(|map, head, goal| {
14028                movement::up(map, head, goal, false, text_layout_details)
14029            })
14030        })
14031    }
14032
14033    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
14034        self.take_rename(true, window, cx);
14035
14036        if self.mode.is_single_line() {
14037            cx.propagate();
14038            return;
14039        }
14040
14041        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14042
14043        let text_layout_details = &self.text_layout_details(window);
14044        let selection_count = self.selections.count();
14045        let first_selection = self.selections.first_anchor();
14046
14047        self.change_selections(Default::default(), window, cx, |s| {
14048            s.move_with(|map, selection| {
14049                if !selection.is_empty() {
14050                    selection.goal = SelectionGoal::None;
14051                }
14052                let (cursor, goal) = movement::down(
14053                    map,
14054                    selection.end,
14055                    selection.goal,
14056                    false,
14057                    text_layout_details,
14058                );
14059                selection.collapse_to(cursor, goal);
14060            });
14061        });
14062
14063        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14064        {
14065            cx.propagate();
14066        }
14067    }
14068
14069    pub fn select_page_down(
14070        &mut self,
14071        _: &SelectPageDown,
14072        window: &mut Window,
14073        cx: &mut Context<Self>,
14074    ) {
14075        let Some(row_count) = self.visible_row_count() else {
14076            return;
14077        };
14078
14079        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14080
14081        let text_layout_details = &self.text_layout_details(window);
14082
14083        self.change_selections(Default::default(), window, cx, |s| {
14084            s.move_heads_with(|map, head, goal| {
14085                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
14086            })
14087        })
14088    }
14089
14090    pub fn move_page_down(
14091        &mut self,
14092        action: &MovePageDown,
14093        window: &mut Window,
14094        cx: &mut Context<Self>,
14095    ) {
14096        if self.take_rename(true, window, cx).is_some() {
14097            return;
14098        }
14099
14100        if self
14101            .context_menu
14102            .borrow_mut()
14103            .as_mut()
14104            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
14105            .unwrap_or(false)
14106        {
14107            return;
14108        }
14109
14110        if matches!(self.mode, EditorMode::SingleLine) {
14111            cx.propagate();
14112            return;
14113        }
14114
14115        let Some(row_count) = self.visible_row_count() else {
14116            return;
14117        };
14118
14119        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14120
14121        let effects = if action.center_cursor {
14122            SelectionEffects::scroll(Autoscroll::center())
14123        } else {
14124            SelectionEffects::default()
14125        };
14126
14127        let text_layout_details = &self.text_layout_details(window);
14128        self.change_selections(effects, window, cx, |s| {
14129            s.move_with(|map, selection| {
14130                if !selection.is_empty() {
14131                    selection.goal = SelectionGoal::None;
14132                }
14133                let (cursor, goal) = movement::down_by_rows(
14134                    map,
14135                    selection.end,
14136                    row_count,
14137                    selection.goal,
14138                    false,
14139                    text_layout_details,
14140                );
14141                selection.collapse_to(cursor, goal);
14142            });
14143        });
14144    }
14145
14146    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
14147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14148        let text_layout_details = &self.text_layout_details(window);
14149        self.change_selections(Default::default(), window, cx, |s| {
14150            s.move_heads_with(|map, head, goal| {
14151                movement::down(map, head, goal, false, text_layout_details)
14152            })
14153        });
14154    }
14155
14156    pub fn context_menu_first(
14157        &mut self,
14158        _: &ContextMenuFirst,
14159        window: &mut Window,
14160        cx: &mut Context<Self>,
14161    ) {
14162        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14163            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14164        }
14165    }
14166
14167    pub fn context_menu_prev(
14168        &mut self,
14169        _: &ContextMenuPrevious,
14170        window: &mut Window,
14171        cx: &mut Context<Self>,
14172    ) {
14173        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14174            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14175        }
14176    }
14177
14178    pub fn context_menu_next(
14179        &mut self,
14180        _: &ContextMenuNext,
14181        window: &mut Window,
14182        cx: &mut Context<Self>,
14183    ) {
14184        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14185            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14186        }
14187    }
14188
14189    pub fn context_menu_last(
14190        &mut self,
14191        _: &ContextMenuLast,
14192        window: &mut Window,
14193        cx: &mut Context<Self>,
14194    ) {
14195        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14196            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14197        }
14198    }
14199
14200    pub fn signature_help_prev(
14201        &mut self,
14202        _: &SignatureHelpPrevious,
14203        _: &mut Window,
14204        cx: &mut Context<Self>,
14205    ) {
14206        if let Some(popover) = self.signature_help_state.popover_mut() {
14207            if popover.current_signature == 0 {
14208                popover.current_signature = popover.signatures.len() - 1;
14209            } else {
14210                popover.current_signature -= 1;
14211            }
14212            cx.notify();
14213        }
14214    }
14215
14216    pub fn signature_help_next(
14217        &mut self,
14218        _: &SignatureHelpNext,
14219        _: &mut Window,
14220        cx: &mut Context<Self>,
14221    ) {
14222        if let Some(popover) = self.signature_help_state.popover_mut() {
14223            if popover.current_signature + 1 == popover.signatures.len() {
14224                popover.current_signature = 0;
14225            } else {
14226                popover.current_signature += 1;
14227            }
14228            cx.notify();
14229        }
14230    }
14231
14232    pub fn move_to_previous_word_start(
14233        &mut self,
14234        _: &MoveToPreviousWordStart,
14235        window: &mut Window,
14236        cx: &mut Context<Self>,
14237    ) {
14238        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14239        self.change_selections(Default::default(), window, cx, |s| {
14240            s.move_cursors_with(|map, head, _| {
14241                (
14242                    movement::previous_word_start(map, head),
14243                    SelectionGoal::None,
14244                )
14245            });
14246        })
14247    }
14248
14249    pub fn move_to_previous_subword_start(
14250        &mut self,
14251        _: &MoveToPreviousSubwordStart,
14252        window: &mut Window,
14253        cx: &mut Context<Self>,
14254    ) {
14255        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14256        self.change_selections(Default::default(), window, cx, |s| {
14257            s.move_cursors_with(|map, head, _| {
14258                (
14259                    movement::previous_subword_start(map, head),
14260                    SelectionGoal::None,
14261                )
14262            });
14263        })
14264    }
14265
14266    pub fn select_to_previous_word_start(
14267        &mut self,
14268        _: &SelectToPreviousWordStart,
14269        window: &mut Window,
14270        cx: &mut Context<Self>,
14271    ) {
14272        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14273        self.change_selections(Default::default(), window, cx, |s| {
14274            s.move_heads_with(|map, head, _| {
14275                (
14276                    movement::previous_word_start(map, head),
14277                    SelectionGoal::None,
14278                )
14279            });
14280        })
14281    }
14282
14283    pub fn select_to_previous_subword_start(
14284        &mut self,
14285        _: &SelectToPreviousSubwordStart,
14286        window: &mut Window,
14287        cx: &mut Context<Self>,
14288    ) {
14289        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14290        self.change_selections(Default::default(), window, cx, |s| {
14291            s.move_heads_with(|map, head, _| {
14292                (
14293                    movement::previous_subword_start(map, head),
14294                    SelectionGoal::None,
14295                )
14296            });
14297        })
14298    }
14299
14300    pub fn delete_to_previous_word_start(
14301        &mut self,
14302        action: &DeleteToPreviousWordStart,
14303        window: &mut Window,
14304        cx: &mut Context<Self>,
14305    ) {
14306        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14307        self.transact(window, cx, |this, window, cx| {
14308            this.select_autoclose_pair(window, cx);
14309            this.change_selections(Default::default(), window, cx, |s| {
14310                s.move_with(|map, selection| {
14311                    if selection.is_empty() {
14312                        let mut cursor = if action.ignore_newlines {
14313                            movement::previous_word_start(map, selection.head())
14314                        } else {
14315                            movement::previous_word_start_or_newline(map, selection.head())
14316                        };
14317                        cursor = movement::adjust_greedy_deletion(
14318                            map,
14319                            selection.head(),
14320                            cursor,
14321                            action.ignore_brackets,
14322                        );
14323                        selection.set_head(cursor, SelectionGoal::None);
14324                    }
14325                });
14326            });
14327            this.insert("", window, cx);
14328        });
14329    }
14330
14331    pub fn delete_to_previous_subword_start(
14332        &mut self,
14333        action: &DeleteToPreviousSubwordStart,
14334        window: &mut Window,
14335        cx: &mut Context<Self>,
14336    ) {
14337        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14338        self.transact(window, cx, |this, window, cx| {
14339            this.select_autoclose_pair(window, cx);
14340            this.change_selections(Default::default(), window, cx, |s| {
14341                s.move_with(|map, selection| {
14342                    if selection.is_empty() {
14343                        let mut cursor = if action.ignore_newlines {
14344                            movement::previous_subword_start(map, selection.head())
14345                        } else {
14346                            movement::previous_subword_start_or_newline(map, selection.head())
14347                        };
14348                        cursor = movement::adjust_greedy_deletion(
14349                            map,
14350                            selection.head(),
14351                            cursor,
14352                            action.ignore_brackets,
14353                        );
14354                        selection.set_head(cursor, SelectionGoal::None);
14355                    }
14356                });
14357            });
14358            this.insert("", window, cx);
14359        });
14360    }
14361
14362    pub fn move_to_next_word_end(
14363        &mut self,
14364        _: &MoveToNextWordEnd,
14365        window: &mut Window,
14366        cx: &mut Context<Self>,
14367    ) {
14368        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14369        self.change_selections(Default::default(), window, cx, |s| {
14370            s.move_cursors_with(|map, head, _| {
14371                (movement::next_word_end(map, head), SelectionGoal::None)
14372            });
14373        })
14374    }
14375
14376    pub fn move_to_next_subword_end(
14377        &mut self,
14378        _: &MoveToNextSubwordEnd,
14379        window: &mut Window,
14380        cx: &mut Context<Self>,
14381    ) {
14382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14383        self.change_selections(Default::default(), window, cx, |s| {
14384            s.move_cursors_with(|map, head, _| {
14385                (movement::next_subword_end(map, head), SelectionGoal::None)
14386            });
14387        })
14388    }
14389
14390    pub fn select_to_next_word_end(
14391        &mut self,
14392        _: &SelectToNextWordEnd,
14393        window: &mut Window,
14394        cx: &mut Context<Self>,
14395    ) {
14396        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14397        self.change_selections(Default::default(), window, cx, |s| {
14398            s.move_heads_with(|map, head, _| {
14399                (movement::next_word_end(map, head), SelectionGoal::None)
14400            });
14401        })
14402    }
14403
14404    pub fn select_to_next_subword_end(
14405        &mut self,
14406        _: &SelectToNextSubwordEnd,
14407        window: &mut Window,
14408        cx: &mut Context<Self>,
14409    ) {
14410        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14411        self.change_selections(Default::default(), window, cx, |s| {
14412            s.move_heads_with(|map, head, _| {
14413                (movement::next_subword_end(map, head), SelectionGoal::None)
14414            });
14415        })
14416    }
14417
14418    pub fn delete_to_next_word_end(
14419        &mut self,
14420        action: &DeleteToNextWordEnd,
14421        window: &mut Window,
14422        cx: &mut Context<Self>,
14423    ) {
14424        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14425        self.transact(window, cx, |this, window, cx| {
14426            this.change_selections(Default::default(), window, cx, |s| {
14427                s.move_with(|map, selection| {
14428                    if selection.is_empty() {
14429                        let mut cursor = if action.ignore_newlines {
14430                            movement::next_word_end(map, selection.head())
14431                        } else {
14432                            movement::next_word_end_or_newline(map, selection.head())
14433                        };
14434                        cursor = movement::adjust_greedy_deletion(
14435                            map,
14436                            selection.head(),
14437                            cursor,
14438                            action.ignore_brackets,
14439                        );
14440                        selection.set_head(cursor, SelectionGoal::None);
14441                    }
14442                });
14443            });
14444            this.insert("", window, cx);
14445        });
14446    }
14447
14448    pub fn delete_to_next_subword_end(
14449        &mut self,
14450        action: &DeleteToNextSubwordEnd,
14451        window: &mut Window,
14452        cx: &mut Context<Self>,
14453    ) {
14454        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14455        self.transact(window, cx, |this, window, cx| {
14456            this.change_selections(Default::default(), window, cx, |s| {
14457                s.move_with(|map, selection| {
14458                    if selection.is_empty() {
14459                        let mut cursor = if action.ignore_newlines {
14460                            movement::next_subword_end(map, selection.head())
14461                        } else {
14462                            movement::next_subword_end_or_newline(map, selection.head())
14463                        };
14464                        cursor = movement::adjust_greedy_deletion(
14465                            map,
14466                            selection.head(),
14467                            cursor,
14468                            action.ignore_brackets,
14469                        );
14470                        selection.set_head(cursor, SelectionGoal::None);
14471                    }
14472                });
14473            });
14474            this.insert("", window, cx);
14475        });
14476    }
14477
14478    pub fn move_to_beginning_of_line(
14479        &mut self,
14480        action: &MoveToBeginningOfLine,
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(|map, head, _| {
14487                (
14488                    movement::indented_line_beginning(
14489                        map,
14490                        head,
14491                        action.stop_at_soft_wraps,
14492                        action.stop_at_indent,
14493                    ),
14494                    SelectionGoal::None,
14495                )
14496            });
14497        })
14498    }
14499
14500    pub fn select_to_beginning_of_line(
14501        &mut self,
14502        action: &SelectToBeginningOfLine,
14503        window: &mut Window,
14504        cx: &mut Context<Self>,
14505    ) {
14506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14507        self.change_selections(Default::default(), window, cx, |s| {
14508            s.move_heads_with(|map, head, _| {
14509                (
14510                    movement::indented_line_beginning(
14511                        map,
14512                        head,
14513                        action.stop_at_soft_wraps,
14514                        action.stop_at_indent,
14515                    ),
14516                    SelectionGoal::None,
14517                )
14518            });
14519        });
14520    }
14521
14522    pub fn delete_to_beginning_of_line(
14523        &mut self,
14524        action: &DeleteToBeginningOfLine,
14525        window: &mut Window,
14526        cx: &mut Context<Self>,
14527    ) {
14528        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14529        self.transact(window, cx, |this, window, cx| {
14530            this.change_selections(Default::default(), window, cx, |s| {
14531                s.move_with(|_, selection| {
14532                    selection.reversed = true;
14533                });
14534            });
14535
14536            this.select_to_beginning_of_line(
14537                &SelectToBeginningOfLine {
14538                    stop_at_soft_wraps: false,
14539                    stop_at_indent: action.stop_at_indent,
14540                },
14541                window,
14542                cx,
14543            );
14544            this.backspace(&Backspace, window, cx);
14545        });
14546    }
14547
14548    pub fn move_to_end_of_line(
14549        &mut self,
14550        action: &MoveToEndOfLine,
14551        window: &mut Window,
14552        cx: &mut Context<Self>,
14553    ) {
14554        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14555        self.change_selections(Default::default(), window, cx, |s| {
14556            s.move_cursors_with(|map, head, _| {
14557                (
14558                    movement::line_end(map, head, action.stop_at_soft_wraps),
14559                    SelectionGoal::None,
14560                )
14561            });
14562        })
14563    }
14564
14565    pub fn select_to_end_of_line(
14566        &mut self,
14567        action: &SelectToEndOfLine,
14568        window: &mut Window,
14569        cx: &mut Context<Self>,
14570    ) {
14571        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14572        self.change_selections(Default::default(), window, cx, |s| {
14573            s.move_heads_with(|map, head, _| {
14574                (
14575                    movement::line_end(map, head, action.stop_at_soft_wraps),
14576                    SelectionGoal::None,
14577                )
14578            });
14579        })
14580    }
14581
14582    pub fn delete_to_end_of_line(
14583        &mut self,
14584        _: &DeleteToEndOfLine,
14585        window: &mut Window,
14586        cx: &mut Context<Self>,
14587    ) {
14588        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14589        self.transact(window, cx, |this, window, cx| {
14590            this.select_to_end_of_line(
14591                &SelectToEndOfLine {
14592                    stop_at_soft_wraps: false,
14593                },
14594                window,
14595                cx,
14596            );
14597            this.delete(&Delete, window, cx);
14598        });
14599    }
14600
14601    pub fn cut_to_end_of_line(
14602        &mut self,
14603        action: &CutToEndOfLine,
14604        window: &mut Window,
14605        cx: &mut Context<Self>,
14606    ) {
14607        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14608        self.transact(window, cx, |this, window, cx| {
14609            this.select_to_end_of_line(
14610                &SelectToEndOfLine {
14611                    stop_at_soft_wraps: false,
14612                },
14613                window,
14614                cx,
14615            );
14616            if !action.stop_at_newlines {
14617                this.change_selections(Default::default(), window, cx, |s| {
14618                    s.move_with(|_, sel| {
14619                        if sel.is_empty() {
14620                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14621                        }
14622                    });
14623                });
14624            }
14625            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14626            let item = this.cut_common(false, window, cx);
14627            cx.write_to_clipboard(item);
14628        });
14629    }
14630
14631    pub fn move_to_start_of_paragraph(
14632        &mut self,
14633        _: &MoveToStartOfParagraph,
14634        window: &mut Window,
14635        cx: &mut Context<Self>,
14636    ) {
14637        if matches!(self.mode, EditorMode::SingleLine) {
14638            cx.propagate();
14639            return;
14640        }
14641        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14642        self.change_selections(Default::default(), window, cx, |s| {
14643            s.move_with(|map, selection| {
14644                selection.collapse_to(
14645                    movement::start_of_paragraph(map, selection.head(), 1),
14646                    SelectionGoal::None,
14647                )
14648            });
14649        })
14650    }
14651
14652    pub fn move_to_end_of_paragraph(
14653        &mut self,
14654        _: &MoveToEndOfParagraph,
14655        window: &mut Window,
14656        cx: &mut Context<Self>,
14657    ) {
14658        if matches!(self.mode, EditorMode::SingleLine) {
14659            cx.propagate();
14660            return;
14661        }
14662        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14663        self.change_selections(Default::default(), window, cx, |s| {
14664            s.move_with(|map, selection| {
14665                selection.collapse_to(
14666                    movement::end_of_paragraph(map, selection.head(), 1),
14667                    SelectionGoal::None,
14668                )
14669            });
14670        })
14671    }
14672
14673    pub fn select_to_start_of_paragraph(
14674        &mut self,
14675        _: &SelectToStartOfParagraph,
14676        window: &mut Window,
14677        cx: &mut Context<Self>,
14678    ) {
14679        if matches!(self.mode, EditorMode::SingleLine) {
14680            cx.propagate();
14681            return;
14682        }
14683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14684        self.change_selections(Default::default(), window, cx, |s| {
14685            s.move_heads_with(|map, head, _| {
14686                (
14687                    movement::start_of_paragraph(map, head, 1),
14688                    SelectionGoal::None,
14689                )
14690            });
14691        })
14692    }
14693
14694    pub fn select_to_end_of_paragraph(
14695        &mut self,
14696        _: &SelectToEndOfParagraph,
14697        window: &mut Window,
14698        cx: &mut Context<Self>,
14699    ) {
14700        if matches!(self.mode, EditorMode::SingleLine) {
14701            cx.propagate();
14702            return;
14703        }
14704        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14705        self.change_selections(Default::default(), window, cx, |s| {
14706            s.move_heads_with(|map, head, _| {
14707                (
14708                    movement::end_of_paragraph(map, head, 1),
14709                    SelectionGoal::None,
14710                )
14711            });
14712        })
14713    }
14714
14715    pub fn move_to_start_of_excerpt(
14716        &mut self,
14717        _: &MoveToStartOfExcerpt,
14718        window: &mut Window,
14719        cx: &mut Context<Self>,
14720    ) {
14721        if matches!(self.mode, EditorMode::SingleLine) {
14722            cx.propagate();
14723            return;
14724        }
14725        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14726        self.change_selections(Default::default(), window, cx, |s| {
14727            s.move_with(|map, selection| {
14728                selection.collapse_to(
14729                    movement::start_of_excerpt(
14730                        map,
14731                        selection.head(),
14732                        workspace::searchable::Direction::Prev,
14733                    ),
14734                    SelectionGoal::None,
14735                )
14736            });
14737        })
14738    }
14739
14740    pub fn move_to_start_of_next_excerpt(
14741        &mut self,
14742        _: &MoveToStartOfNextExcerpt,
14743        window: &mut Window,
14744        cx: &mut Context<Self>,
14745    ) {
14746        if matches!(self.mode, EditorMode::SingleLine) {
14747            cx.propagate();
14748            return;
14749        }
14750
14751        self.change_selections(Default::default(), window, cx, |s| {
14752            s.move_with(|map, selection| {
14753                selection.collapse_to(
14754                    movement::start_of_excerpt(
14755                        map,
14756                        selection.head(),
14757                        workspace::searchable::Direction::Next,
14758                    ),
14759                    SelectionGoal::None,
14760                )
14761            });
14762        })
14763    }
14764
14765    pub fn move_to_end_of_excerpt(
14766        &mut self,
14767        _: &MoveToEndOfExcerpt,
14768        window: &mut Window,
14769        cx: &mut Context<Self>,
14770    ) {
14771        if matches!(self.mode, EditorMode::SingleLine) {
14772            cx.propagate();
14773            return;
14774        }
14775        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14776        self.change_selections(Default::default(), window, cx, |s| {
14777            s.move_with(|map, selection| {
14778                selection.collapse_to(
14779                    movement::end_of_excerpt(
14780                        map,
14781                        selection.head(),
14782                        workspace::searchable::Direction::Next,
14783                    ),
14784                    SelectionGoal::None,
14785                )
14786            });
14787        })
14788    }
14789
14790    pub fn move_to_end_of_previous_excerpt(
14791        &mut self,
14792        _: &MoveToEndOfPreviousExcerpt,
14793        window: &mut Window,
14794        cx: &mut Context<Self>,
14795    ) {
14796        if matches!(self.mode, EditorMode::SingleLine) {
14797            cx.propagate();
14798            return;
14799        }
14800        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14801        self.change_selections(Default::default(), window, cx, |s| {
14802            s.move_with(|map, selection| {
14803                selection.collapse_to(
14804                    movement::end_of_excerpt(
14805                        map,
14806                        selection.head(),
14807                        workspace::searchable::Direction::Prev,
14808                    ),
14809                    SelectionGoal::None,
14810                )
14811            });
14812        })
14813    }
14814
14815    pub fn select_to_start_of_excerpt(
14816        &mut self,
14817        _: &SelectToStartOfExcerpt,
14818        window: &mut Window,
14819        cx: &mut Context<Self>,
14820    ) {
14821        if matches!(self.mode, EditorMode::SingleLine) {
14822            cx.propagate();
14823            return;
14824        }
14825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14826        self.change_selections(Default::default(), window, cx, |s| {
14827            s.move_heads_with(|map, head, _| {
14828                (
14829                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14830                    SelectionGoal::None,
14831                )
14832            });
14833        })
14834    }
14835
14836    pub fn select_to_start_of_next_excerpt(
14837        &mut self,
14838        _: &SelectToStartOfNextExcerpt,
14839        window: &mut Window,
14840        cx: &mut Context<Self>,
14841    ) {
14842        if matches!(self.mode, EditorMode::SingleLine) {
14843            cx.propagate();
14844            return;
14845        }
14846        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14847        self.change_selections(Default::default(), window, cx, |s| {
14848            s.move_heads_with(|map, head, _| {
14849                (
14850                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14851                    SelectionGoal::None,
14852                )
14853            });
14854        })
14855    }
14856
14857    pub fn select_to_end_of_excerpt(
14858        &mut self,
14859        _: &SelectToEndOfExcerpt,
14860        window: &mut Window,
14861        cx: &mut Context<Self>,
14862    ) {
14863        if matches!(self.mode, EditorMode::SingleLine) {
14864            cx.propagate();
14865            return;
14866        }
14867        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14868        self.change_selections(Default::default(), window, cx, |s| {
14869            s.move_heads_with(|map, head, _| {
14870                (
14871                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14872                    SelectionGoal::None,
14873                )
14874            });
14875        })
14876    }
14877
14878    pub fn select_to_end_of_previous_excerpt(
14879        &mut self,
14880        _: &SelectToEndOfPreviousExcerpt,
14881        window: &mut Window,
14882        cx: &mut Context<Self>,
14883    ) {
14884        if matches!(self.mode, EditorMode::SingleLine) {
14885            cx.propagate();
14886            return;
14887        }
14888        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14889        self.change_selections(Default::default(), window, cx, |s| {
14890            s.move_heads_with(|map, head, _| {
14891                (
14892                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14893                    SelectionGoal::None,
14894                )
14895            });
14896        })
14897    }
14898
14899    pub fn move_to_beginning(
14900        &mut self,
14901        _: &MoveToBeginning,
14902        window: &mut Window,
14903        cx: &mut Context<Self>,
14904    ) {
14905        if matches!(self.mode, EditorMode::SingleLine) {
14906            cx.propagate();
14907            return;
14908        }
14909        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14910        self.change_selections(Default::default(), window, cx, |s| {
14911            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14912        });
14913    }
14914
14915    pub fn select_to_beginning(
14916        &mut self,
14917        _: &SelectToBeginning,
14918        window: &mut Window,
14919        cx: &mut Context<Self>,
14920    ) {
14921        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14922        selection.set_head(Point::zero(), SelectionGoal::None);
14923        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14924        self.change_selections(Default::default(), window, cx, |s| {
14925            s.select(vec![selection]);
14926        });
14927    }
14928
14929    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14930        if matches!(self.mode, EditorMode::SingleLine) {
14931            cx.propagate();
14932            return;
14933        }
14934        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14935        let cursor = self.buffer.read(cx).read(cx).len();
14936        self.change_selections(Default::default(), window, cx, |s| {
14937            s.select_ranges(vec![cursor..cursor])
14938        });
14939    }
14940
14941    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14942        self.nav_history = nav_history;
14943    }
14944
14945    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14946        self.nav_history.as_ref()
14947    }
14948
14949    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14950        self.push_to_nav_history(
14951            self.selections.newest_anchor().head(),
14952            None,
14953            false,
14954            true,
14955            cx,
14956        );
14957    }
14958
14959    fn navigation_data(&self, cursor_anchor: Anchor, cx: &App) -> NavigationData {
14960        let buffer = self.buffer.read(cx).read(cx);
14961        let cursor_position = cursor_anchor.to_point(&buffer);
14962        let scroll_anchor = self.scroll_manager.anchor();
14963        let scroll_top_row = scroll_anchor.top_row(&buffer);
14964        drop(buffer);
14965
14966        NavigationData {
14967            cursor_anchor,
14968            cursor_position,
14969            scroll_anchor,
14970            scroll_top_row,
14971        }
14972    }
14973
14974    fn navigation_entry(&self, cursor_anchor: Anchor, cx: &App) -> Option<NavigationEntry> {
14975        let Some(history) = self.nav_history.clone() else {
14976            return None;
14977        };
14978        let data = self.navigation_data(cursor_anchor, cx);
14979        Some(history.navigation_entry(Some(Arc::new(data) as Arc<dyn Any + Send + Sync>)))
14980    }
14981
14982    fn push_to_nav_history(
14983        &mut self,
14984        cursor_anchor: Anchor,
14985        new_position: Option<Point>,
14986        is_deactivate: bool,
14987        always: bool,
14988        cx: &mut Context<Self>,
14989    ) {
14990        let data = self.navigation_data(cursor_anchor, cx);
14991        if let Some(nav_history) = self.nav_history.as_mut() {
14992            if let Some(new_position) = new_position {
14993                let row_delta = (new_position.row as i64 - data.cursor_position.row as i64).abs();
14994                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14995                    return;
14996                }
14997            }
14998
14999            nav_history.push(Some(data), cx);
15000            cx.emit(EditorEvent::PushedToNavHistory {
15001                anchor: cursor_anchor,
15002                is_deactivate,
15003            })
15004        }
15005    }
15006
15007    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
15008        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15009        let buffer = self.buffer.read(cx).snapshot(cx);
15010        let mut selection = self
15011            .selections
15012            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
15013        selection.set_head(buffer.len(), SelectionGoal::None);
15014        self.change_selections(Default::default(), window, cx, |s| {
15015            s.select(vec![selection]);
15016        });
15017    }
15018
15019    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
15020        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15021        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15022            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
15023        });
15024    }
15025
15026    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
15027        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15028        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15029        let mut selections = self.selections.all::<Point>(&display_map);
15030        let max_point = display_map.buffer_snapshot().max_point();
15031        for selection in &mut selections {
15032            let rows = selection.spanned_rows(true, &display_map);
15033            selection.start = Point::new(rows.start.0, 0);
15034            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
15035            selection.reversed = false;
15036        }
15037        self.change_selections(Default::default(), window, cx, |s| {
15038            s.select(selections);
15039        });
15040    }
15041
15042    pub fn split_selection_into_lines(
15043        &mut self,
15044        action: &SplitSelectionIntoLines,
15045        window: &mut Window,
15046        cx: &mut Context<Self>,
15047    ) {
15048        let selections = self
15049            .selections
15050            .all::<Point>(&self.display_snapshot(cx))
15051            .into_iter()
15052            .map(|selection| selection.start..selection.end)
15053            .collect::<Vec<_>>();
15054        self.unfold_ranges(&selections, true, true, cx);
15055
15056        let mut new_selection_ranges = Vec::new();
15057        {
15058            let buffer = self.buffer.read(cx).read(cx);
15059            for selection in selections {
15060                for row in selection.start.row..selection.end.row {
15061                    let line_start = Point::new(row, 0);
15062                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
15063
15064                    if action.keep_selections {
15065                        // Keep the selection range for each line
15066                        let selection_start = if row == selection.start.row {
15067                            selection.start
15068                        } else {
15069                            line_start
15070                        };
15071                        new_selection_ranges.push(selection_start..line_end);
15072                    } else {
15073                        // Collapse to cursor at end of line
15074                        new_selection_ranges.push(line_end..line_end);
15075                    }
15076                }
15077
15078                let is_multiline_selection = selection.start.row != selection.end.row;
15079                // Don't insert last one if it's a multi-line selection ending at the start of a line,
15080                // so this action feels more ergonomic when paired with other selection operations
15081                let should_skip_last = is_multiline_selection && selection.end.column == 0;
15082                if !should_skip_last {
15083                    if action.keep_selections {
15084                        if is_multiline_selection {
15085                            let line_start = Point::new(selection.end.row, 0);
15086                            new_selection_ranges.push(line_start..selection.end);
15087                        } else {
15088                            new_selection_ranges.push(selection.start..selection.end);
15089                        }
15090                    } else {
15091                        new_selection_ranges.push(selection.end..selection.end);
15092                    }
15093                }
15094            }
15095        }
15096        self.change_selections(Default::default(), window, cx, |s| {
15097            s.select_ranges(new_selection_ranges);
15098        });
15099    }
15100
15101    pub fn add_selection_above(
15102        &mut self,
15103        action: &AddSelectionAbove,
15104        window: &mut Window,
15105        cx: &mut Context<Self>,
15106    ) {
15107        self.add_selection(true, action.skip_soft_wrap, window, cx);
15108    }
15109
15110    pub fn add_selection_below(
15111        &mut self,
15112        action: &AddSelectionBelow,
15113        window: &mut Window,
15114        cx: &mut Context<Self>,
15115    ) {
15116        self.add_selection(false, action.skip_soft_wrap, window, cx);
15117    }
15118
15119    fn add_selection(
15120        &mut self,
15121        above: bool,
15122        skip_soft_wrap: bool,
15123        window: &mut Window,
15124        cx: &mut Context<Self>,
15125    ) {
15126        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15127
15128        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15129        let all_selections = self.selections.all::<Point>(&display_map);
15130        let text_layout_details = self.text_layout_details(window);
15131
15132        let (mut columnar_selections, new_selections_to_columnarize) = {
15133            if let Some(state) = self.add_selections_state.as_ref() {
15134                let columnar_selection_ids: HashSet<_> = state
15135                    .groups
15136                    .iter()
15137                    .flat_map(|group| group.stack.iter())
15138                    .copied()
15139                    .collect();
15140
15141                all_selections
15142                    .into_iter()
15143                    .partition(|s| columnar_selection_ids.contains(&s.id))
15144            } else {
15145                (Vec::new(), all_selections)
15146            }
15147        };
15148
15149        let mut state = self
15150            .add_selections_state
15151            .take()
15152            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
15153
15154        for selection in new_selections_to_columnarize {
15155            let range = selection.display_range(&display_map).sorted();
15156            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
15157            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
15158            let positions = start_x.min(end_x)..start_x.max(end_x);
15159            let mut stack = Vec::new();
15160            for row in range.start.row().0..=range.end.row().0 {
15161                if let Some(selection) = self.selections.build_columnar_selection(
15162                    &display_map,
15163                    DisplayRow(row),
15164                    &positions,
15165                    selection.reversed,
15166                    &text_layout_details,
15167                ) {
15168                    stack.push(selection.id);
15169                    columnar_selections.push(selection);
15170                }
15171            }
15172            if !stack.is_empty() {
15173                if above {
15174                    stack.reverse();
15175                }
15176                state.groups.push(AddSelectionsGroup { above, stack });
15177            }
15178        }
15179
15180        let mut final_selections = Vec::new();
15181        let end_row = if above {
15182            DisplayRow(0)
15183        } else {
15184            display_map.max_point().row()
15185        };
15186
15187        // When `skip_soft_wrap` is true, we use buffer columns instead of pixel
15188        // positions to place new selections, so we need to keep track of the
15189        // column range of the oldest selection in each group, because
15190        // intermediate selections may have been clamped to shorter lines.
15191        // selections may have been clamped to shorter lines.
15192        let mut goal_columns_by_selection_id = if skip_soft_wrap {
15193            let mut map = HashMap::default();
15194            for group in state.groups.iter() {
15195                if let Some(oldest_id) = group.stack.first() {
15196                    if let Some(oldest_selection) =
15197                        columnar_selections.iter().find(|s| s.id == *oldest_id)
15198                    {
15199                        let start_col = oldest_selection.start.column;
15200                        let end_col = oldest_selection.end.column;
15201                        let goal_columns = start_col.min(end_col)..start_col.max(end_col);
15202                        for id in &group.stack {
15203                            map.insert(*id, goal_columns.clone());
15204                        }
15205                    }
15206                }
15207            }
15208            map
15209        } else {
15210            HashMap::default()
15211        };
15212
15213        let mut last_added_item_per_group = HashMap::default();
15214        for group in state.groups.iter_mut() {
15215            if let Some(last_id) = group.stack.last() {
15216                last_added_item_per_group.insert(*last_id, group);
15217            }
15218        }
15219
15220        for selection in columnar_selections {
15221            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15222                if above == group.above {
15223                    let range = selection.display_range(&display_map).sorted();
15224                    debug_assert_eq!(range.start.row(), range.end.row());
15225                    let row = range.start.row();
15226                    let positions =
15227                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15228                            Pixels::from(start)..Pixels::from(end)
15229                        } else {
15230                            let start_x =
15231                                display_map.x_for_display_point(range.start, &text_layout_details);
15232                            let end_x =
15233                                display_map.x_for_display_point(range.end, &text_layout_details);
15234                            start_x.min(end_x)..start_x.max(end_x)
15235                        };
15236
15237                    let maybe_new_selection = if skip_soft_wrap {
15238                        let goal_columns = goal_columns_by_selection_id
15239                            .remove(&selection.id)
15240                            .unwrap_or_else(|| {
15241                                let start_col = selection.start.column;
15242                                let end_col = selection.end.column;
15243                                start_col.min(end_col)..start_col.max(end_col)
15244                            });
15245                        self.selections.find_next_columnar_selection_by_buffer_row(
15246                            &display_map,
15247                            row,
15248                            end_row,
15249                            above,
15250                            &goal_columns,
15251                            selection.reversed,
15252                            &text_layout_details,
15253                        )
15254                    } else {
15255                        self.selections.find_next_columnar_selection_by_display_row(
15256                            &display_map,
15257                            row,
15258                            end_row,
15259                            above,
15260                            &positions,
15261                            selection.reversed,
15262                            &text_layout_details,
15263                        )
15264                    };
15265
15266                    if let Some(new_selection) = maybe_new_selection {
15267                        group.stack.push(new_selection.id);
15268                        if above {
15269                            final_selections.push(new_selection);
15270                            final_selections.push(selection);
15271                        } else {
15272                            final_selections.push(selection);
15273                            final_selections.push(new_selection);
15274                        }
15275                    } else {
15276                        final_selections.push(selection);
15277                    }
15278                } else {
15279                    group.stack.pop();
15280                }
15281            } else {
15282                final_selections.push(selection);
15283            }
15284        }
15285
15286        self.change_selections(Default::default(), window, cx, |s| {
15287            s.select(final_selections);
15288        });
15289
15290        let final_selection_ids: HashSet<_> = self
15291            .selections
15292            .all::<Point>(&display_map)
15293            .iter()
15294            .map(|s| s.id)
15295            .collect();
15296        state.groups.retain_mut(|group| {
15297            // selections might get merged above so we remove invalid items from stacks
15298            group.stack.retain(|id| final_selection_ids.contains(id));
15299
15300            // single selection in stack can be treated as initial state
15301            group.stack.len() > 1
15302        });
15303
15304        if !state.groups.is_empty() {
15305            self.add_selections_state = Some(state);
15306        }
15307    }
15308
15309    pub fn insert_snippet_at_selections(
15310        &mut self,
15311        action: &InsertSnippet,
15312        window: &mut Window,
15313        cx: &mut Context<Self>,
15314    ) {
15315        self.try_insert_snippet_at_selections(action, window, cx)
15316            .log_err();
15317    }
15318
15319    fn try_insert_snippet_at_selections(
15320        &mut self,
15321        action: &InsertSnippet,
15322        window: &mut Window,
15323        cx: &mut Context<Self>,
15324    ) -> Result<()> {
15325        let insertion_ranges = self
15326            .selections
15327            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15328            .into_iter()
15329            .map(|selection| selection.range())
15330            .collect_vec();
15331
15332        let snippet = if let Some(snippet_body) = &action.snippet {
15333            if action.language.is_none() && action.name.is_none() {
15334                Snippet::parse(snippet_body)?
15335            } else {
15336                bail!("`snippet` is mutually exclusive with `language` and `name`")
15337            }
15338        } else if let Some(name) = &action.name {
15339            let project = self.project().context("no project")?;
15340            let snippet_store = project.read(cx).snippets().read(cx);
15341            let snippet = snippet_store
15342                .snippets_for(action.language.clone(), cx)
15343                .into_iter()
15344                .find(|snippet| snippet.name == *name)
15345                .context("snippet not found")?;
15346            Snippet::parse(&snippet.body)?
15347        } else {
15348            // todo(andrew): open modal to select snippet
15349            bail!("`name` or `snippet` is required")
15350        };
15351
15352        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15353    }
15354
15355    fn select_match_ranges(
15356        &mut self,
15357        range: Range<MultiBufferOffset>,
15358        reversed: bool,
15359        replace_newest: bool,
15360        auto_scroll: Option<Autoscroll>,
15361        window: &mut Window,
15362        cx: &mut Context<Editor>,
15363    ) {
15364        self.unfold_ranges(
15365            std::slice::from_ref(&range),
15366            false,
15367            auto_scroll.is_some(),
15368            cx,
15369        );
15370        let effects = if let Some(scroll) = auto_scroll {
15371            SelectionEffects::scroll(scroll)
15372        } else {
15373            SelectionEffects::no_scroll()
15374        };
15375        self.change_selections(effects, window, cx, |s| {
15376            if replace_newest {
15377                s.delete(s.newest_anchor().id);
15378            }
15379            if reversed {
15380                s.insert_range(range.end..range.start);
15381            } else {
15382                s.insert_range(range);
15383            }
15384        });
15385    }
15386
15387    pub fn select_next_match_internal(
15388        &mut self,
15389        display_map: &DisplaySnapshot,
15390        replace_newest: bool,
15391        autoscroll: Option<Autoscroll>,
15392        window: &mut Window,
15393        cx: &mut Context<Self>,
15394    ) -> Result<()> {
15395        let buffer = display_map.buffer_snapshot();
15396        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15397        if let Some(mut select_next_state) = self.select_next_state.take() {
15398            let query = &select_next_state.query;
15399            if !select_next_state.done {
15400                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15401                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15402                let mut next_selected_range = None;
15403
15404                let bytes_after_last_selection =
15405                    buffer.bytes_in_range(last_selection.end..buffer.len());
15406                let bytes_before_first_selection =
15407                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15408                let query_matches = query
15409                    .stream_find_iter(bytes_after_last_selection)
15410                    .map(|result| (last_selection.end, result))
15411                    .chain(
15412                        query
15413                            .stream_find_iter(bytes_before_first_selection)
15414                            .map(|result| (MultiBufferOffset(0), result)),
15415                    );
15416
15417                for (start_offset, query_match) in query_matches {
15418                    let query_match = query_match.unwrap(); // can only fail due to I/O
15419                    let offset_range =
15420                        start_offset + query_match.start()..start_offset + query_match.end();
15421
15422                    if !select_next_state.wordwise
15423                        || (!buffer.is_inside_word(offset_range.start, None)
15424                            && !buffer.is_inside_word(offset_range.end, None))
15425                    {
15426                        let idx = selections
15427                            .partition_point(|selection| selection.end <= offset_range.start);
15428                        let overlaps = selections
15429                            .get(idx)
15430                            .map_or(false, |selection| selection.start < offset_range.end);
15431
15432                        if !overlaps {
15433                            next_selected_range = Some(offset_range);
15434                            break;
15435                        }
15436                    }
15437                }
15438
15439                if let Some(next_selected_range) = next_selected_range {
15440                    self.select_match_ranges(
15441                        next_selected_range,
15442                        last_selection.reversed,
15443                        replace_newest,
15444                        autoscroll,
15445                        window,
15446                        cx,
15447                    );
15448                } else {
15449                    select_next_state.done = true;
15450                }
15451            }
15452
15453            self.select_next_state = Some(select_next_state);
15454        } else {
15455            let mut only_carets = true;
15456            let mut same_text_selected = true;
15457            let mut selected_text = None;
15458
15459            let mut selections_iter = selections.iter().peekable();
15460            while let Some(selection) = selections_iter.next() {
15461                if selection.start != selection.end {
15462                    only_carets = false;
15463                }
15464
15465                if same_text_selected {
15466                    if selected_text.is_none() {
15467                        selected_text =
15468                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15469                    }
15470
15471                    if let Some(next_selection) = selections_iter.peek() {
15472                        if next_selection.len() == selection.len() {
15473                            let next_selected_text = buffer
15474                                .text_for_range(next_selection.range())
15475                                .collect::<String>();
15476                            if Some(next_selected_text) != selected_text {
15477                                same_text_selected = false;
15478                                selected_text = None;
15479                            }
15480                        } else {
15481                            same_text_selected = false;
15482                            selected_text = None;
15483                        }
15484                    }
15485                }
15486            }
15487
15488            if only_carets {
15489                for selection in &mut selections {
15490                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15491                    selection.start = word_range.start;
15492                    selection.end = word_range.end;
15493                    selection.goal = SelectionGoal::None;
15494                    selection.reversed = false;
15495                    self.select_match_ranges(
15496                        selection.start..selection.end,
15497                        selection.reversed,
15498                        replace_newest,
15499                        autoscroll,
15500                        window,
15501                        cx,
15502                    );
15503                }
15504
15505                if selections.len() == 1 {
15506                    let selection = selections
15507                        .last()
15508                        .expect("ensured that there's only one selection");
15509                    let query = buffer
15510                        .text_for_range(selection.start..selection.end)
15511                        .collect::<String>();
15512                    let is_empty = query.is_empty();
15513                    let select_state = SelectNextState {
15514                        query: self.build_query(&[query], cx)?,
15515                        wordwise: true,
15516                        done: is_empty,
15517                    };
15518                    self.select_next_state = Some(select_state);
15519                } else {
15520                    self.select_next_state = None;
15521                }
15522            } else if let Some(selected_text) = selected_text {
15523                self.select_next_state = Some(SelectNextState {
15524                    query: self.build_query(&[selected_text], cx)?,
15525                    wordwise: false,
15526                    done: false,
15527                });
15528                self.select_next_match_internal(
15529                    display_map,
15530                    replace_newest,
15531                    autoscroll,
15532                    window,
15533                    cx,
15534                )?;
15535            }
15536        }
15537        Ok(())
15538    }
15539
15540    pub fn select_all_matches(
15541        &mut self,
15542        _action: &SelectAllMatches,
15543        window: &mut Window,
15544        cx: &mut Context<Self>,
15545    ) -> Result<()> {
15546        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15547
15548        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15549
15550        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15551        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
15552        else {
15553            return Ok(());
15554        };
15555
15556        let mut new_selections = Vec::new();
15557
15558        let reversed = self
15559            .selections
15560            .oldest::<MultiBufferOffset>(&display_map)
15561            .reversed;
15562        let buffer = display_map.buffer_snapshot();
15563        let query_matches = select_next_state
15564            .query
15565            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15566
15567        for query_match in query_matches.into_iter() {
15568            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15569            let offset_range = if reversed {
15570                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15571            } else {
15572                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15573            };
15574
15575            if !select_next_state.wordwise
15576                || (!buffer.is_inside_word(offset_range.start, None)
15577                    && !buffer.is_inside_word(offset_range.end, None))
15578            {
15579                new_selections.push(offset_range.start..offset_range.end);
15580            }
15581        }
15582
15583        select_next_state.done = true;
15584
15585        if new_selections.is_empty() {
15586            log::error!("bug: new_selections is empty in select_all_matches");
15587            return Ok(());
15588        }
15589
15590        self.unfold_ranges(&new_selections, false, false, cx);
15591        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15592            selections.select_ranges(new_selections)
15593        });
15594
15595        Ok(())
15596    }
15597
15598    pub fn select_next(
15599        &mut self,
15600        action: &SelectNext,
15601        window: &mut Window,
15602        cx: &mut Context<Self>,
15603    ) -> Result<()> {
15604        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15605        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15606        self.select_next_match_internal(
15607            &display_map,
15608            action.replace_newest,
15609            Some(Autoscroll::newest()),
15610            window,
15611            cx,
15612        )
15613    }
15614
15615    pub fn select_previous(
15616        &mut self,
15617        action: &SelectPrevious,
15618        window: &mut Window,
15619        cx: &mut Context<Self>,
15620    ) -> Result<()> {
15621        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15622        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15623        let buffer = display_map.buffer_snapshot();
15624        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15625        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15626            let query = &select_prev_state.query;
15627            if !select_prev_state.done {
15628                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15629                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15630                let mut next_selected_range = None;
15631                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15632                let bytes_before_last_selection =
15633                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15634                let bytes_after_first_selection =
15635                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15636                let query_matches = query
15637                    .stream_find_iter(bytes_before_last_selection)
15638                    .map(|result| (last_selection.start, result))
15639                    .chain(
15640                        query
15641                            .stream_find_iter(bytes_after_first_selection)
15642                            .map(|result| (buffer.len(), result)),
15643                    );
15644                for (end_offset, query_match) in query_matches {
15645                    let query_match = query_match.unwrap(); // can only fail due to I/O
15646                    let offset_range =
15647                        end_offset - query_match.end()..end_offset - query_match.start();
15648
15649                    if !select_prev_state.wordwise
15650                        || (!buffer.is_inside_word(offset_range.start, None)
15651                            && !buffer.is_inside_word(offset_range.end, None))
15652                    {
15653                        next_selected_range = Some(offset_range);
15654                        break;
15655                    }
15656                }
15657
15658                if let Some(next_selected_range) = next_selected_range {
15659                    self.select_match_ranges(
15660                        next_selected_range,
15661                        last_selection.reversed,
15662                        action.replace_newest,
15663                        Some(Autoscroll::newest()),
15664                        window,
15665                        cx,
15666                    );
15667                } else {
15668                    select_prev_state.done = true;
15669                }
15670            }
15671
15672            self.select_prev_state = Some(select_prev_state);
15673        } else {
15674            let mut only_carets = true;
15675            let mut same_text_selected = true;
15676            let mut selected_text = None;
15677
15678            let mut selections_iter = selections.iter().peekable();
15679            while let Some(selection) = selections_iter.next() {
15680                if selection.start != selection.end {
15681                    only_carets = false;
15682                }
15683
15684                if same_text_selected {
15685                    if selected_text.is_none() {
15686                        selected_text =
15687                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15688                    }
15689
15690                    if let Some(next_selection) = selections_iter.peek() {
15691                        if next_selection.len() == selection.len() {
15692                            let next_selected_text = buffer
15693                                .text_for_range(next_selection.range())
15694                                .collect::<String>();
15695                            if Some(next_selected_text) != selected_text {
15696                                same_text_selected = false;
15697                                selected_text = None;
15698                            }
15699                        } else {
15700                            same_text_selected = false;
15701                            selected_text = None;
15702                        }
15703                    }
15704                }
15705            }
15706
15707            if only_carets {
15708                for selection in &mut selections {
15709                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15710                    selection.start = word_range.start;
15711                    selection.end = word_range.end;
15712                    selection.goal = SelectionGoal::None;
15713                    selection.reversed = false;
15714                    self.select_match_ranges(
15715                        selection.start..selection.end,
15716                        selection.reversed,
15717                        action.replace_newest,
15718                        Some(Autoscroll::newest()),
15719                        window,
15720                        cx,
15721                    );
15722                }
15723                if selections.len() == 1 {
15724                    let selection = selections
15725                        .last()
15726                        .expect("ensured that there's only one selection");
15727                    let query = buffer
15728                        .text_for_range(selection.start..selection.end)
15729                        .collect::<String>();
15730                    let is_empty = query.is_empty();
15731                    let select_state = SelectNextState {
15732                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15733                        wordwise: true,
15734                        done: is_empty,
15735                    };
15736                    self.select_prev_state = Some(select_state);
15737                } else {
15738                    self.select_prev_state = None;
15739                }
15740            } else if let Some(selected_text) = selected_text {
15741                self.select_prev_state = Some(SelectNextState {
15742                    query: self
15743                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15744                    wordwise: false,
15745                    done: false,
15746                });
15747                self.select_previous(action, window, cx)?;
15748            }
15749        }
15750        Ok(())
15751    }
15752
15753    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15754    /// setting the case sensitivity based on the global
15755    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15756    /// editor's settings.
15757    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15758    where
15759        I: IntoIterator<Item = P>,
15760        P: AsRef<[u8]>,
15761    {
15762        let case_sensitive = self
15763            .select_next_is_case_sensitive
15764            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15765
15766        let mut builder = AhoCorasickBuilder::new();
15767        builder.ascii_case_insensitive(!case_sensitive);
15768        builder.build(patterns)
15769    }
15770
15771    pub fn find_next_match(
15772        &mut self,
15773        _: &FindNextMatch,
15774        window: &mut Window,
15775        cx: &mut Context<Self>,
15776    ) -> Result<()> {
15777        let selections = self.selections.disjoint_anchors_arc();
15778        match selections.first() {
15779            Some(first) if selections.len() >= 2 => {
15780                self.change_selections(Default::default(), window, cx, |s| {
15781                    s.select_ranges([first.range()]);
15782                });
15783            }
15784            _ => self.select_next(
15785                &SelectNext {
15786                    replace_newest: true,
15787                },
15788                window,
15789                cx,
15790            )?,
15791        }
15792        Ok(())
15793    }
15794
15795    pub fn find_previous_match(
15796        &mut self,
15797        _: &FindPreviousMatch,
15798        window: &mut Window,
15799        cx: &mut Context<Self>,
15800    ) -> Result<()> {
15801        let selections = self.selections.disjoint_anchors_arc();
15802        match selections.last() {
15803            Some(last) if selections.len() >= 2 => {
15804                self.change_selections(Default::default(), window, cx, |s| {
15805                    s.select_ranges([last.range()]);
15806                });
15807            }
15808            _ => self.select_previous(
15809                &SelectPrevious {
15810                    replace_newest: true,
15811                },
15812                window,
15813                cx,
15814            )?,
15815        }
15816        Ok(())
15817    }
15818
15819    pub fn toggle_comments(
15820        &mut self,
15821        action: &ToggleComments,
15822        window: &mut Window,
15823        cx: &mut Context<Self>,
15824    ) {
15825        if self.read_only(cx) {
15826            return;
15827        }
15828        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15829        let text_layout_details = &self.text_layout_details(window);
15830        self.transact(window, cx, |this, window, cx| {
15831            let mut selections = this
15832                .selections
15833                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15834            let mut edits = Vec::new();
15835            let mut selection_edit_ranges = Vec::new();
15836            let mut last_toggled_row = None;
15837            let snapshot = this.buffer.read(cx).read(cx);
15838            let empty_str: Arc<str> = Arc::default();
15839            let mut suffixes_inserted = Vec::new();
15840            let ignore_indent = action.ignore_indent;
15841
15842            fn comment_prefix_range(
15843                snapshot: &MultiBufferSnapshot,
15844                row: MultiBufferRow,
15845                comment_prefix: &str,
15846                comment_prefix_whitespace: &str,
15847                ignore_indent: bool,
15848            ) -> Range<Point> {
15849                let indent_size = if ignore_indent {
15850                    0
15851                } else {
15852                    snapshot.indent_size_for_line(row).len
15853                };
15854
15855                let start = Point::new(row.0, indent_size);
15856
15857                let mut line_bytes = snapshot
15858                    .bytes_in_range(start..snapshot.max_point())
15859                    .flatten()
15860                    .copied();
15861
15862                // If this line currently begins with the line comment prefix, then record
15863                // the range containing the prefix.
15864                if line_bytes
15865                    .by_ref()
15866                    .take(comment_prefix.len())
15867                    .eq(comment_prefix.bytes())
15868                {
15869                    // Include any whitespace that matches the comment prefix.
15870                    let matching_whitespace_len = line_bytes
15871                        .zip(comment_prefix_whitespace.bytes())
15872                        .take_while(|(a, b)| a == b)
15873                        .count() as u32;
15874                    let end = Point::new(
15875                        start.row,
15876                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15877                    );
15878                    start..end
15879                } else {
15880                    start..start
15881                }
15882            }
15883
15884            fn comment_suffix_range(
15885                snapshot: &MultiBufferSnapshot,
15886                row: MultiBufferRow,
15887                comment_suffix: &str,
15888                comment_suffix_has_leading_space: bool,
15889            ) -> Range<Point> {
15890                let end = Point::new(row.0, snapshot.line_len(row));
15891                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15892
15893                let mut line_end_bytes = snapshot
15894                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15895                    .flatten()
15896                    .copied();
15897
15898                let leading_space_len = if suffix_start_column > 0
15899                    && line_end_bytes.next() == Some(b' ')
15900                    && comment_suffix_has_leading_space
15901                {
15902                    1
15903                } else {
15904                    0
15905                };
15906
15907                // If this line currently begins with the line comment prefix, then record
15908                // the range containing the prefix.
15909                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15910                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15911                    start..end
15912                } else {
15913                    end..end
15914                }
15915            }
15916
15917            // TODO: Handle selections that cross excerpts
15918            for selection in &mut selections {
15919                let start_column = snapshot
15920                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15921                    .len;
15922                let language = if let Some(language) =
15923                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15924                {
15925                    language
15926                } else {
15927                    continue;
15928                };
15929
15930                selection_edit_ranges.clear();
15931
15932                // If multiple selections contain a given row, avoid processing that
15933                // row more than once.
15934                let mut start_row = MultiBufferRow(selection.start.row);
15935                if last_toggled_row == Some(start_row) {
15936                    start_row = start_row.next_row();
15937                }
15938                let end_row =
15939                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15940                        MultiBufferRow(selection.end.row - 1)
15941                    } else {
15942                        MultiBufferRow(selection.end.row)
15943                    };
15944                last_toggled_row = Some(end_row);
15945
15946                if start_row > end_row {
15947                    continue;
15948                }
15949
15950                // If the language has line comments, toggle those.
15951                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15952
15953                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15954                if ignore_indent {
15955                    full_comment_prefixes = full_comment_prefixes
15956                        .into_iter()
15957                        .map(|s| Arc::from(s.trim_end()))
15958                        .collect();
15959                }
15960
15961                if !full_comment_prefixes.is_empty() {
15962                    let first_prefix = full_comment_prefixes
15963                        .first()
15964                        .expect("prefixes is non-empty");
15965                    let prefix_trimmed_lengths = full_comment_prefixes
15966                        .iter()
15967                        .map(|p| p.trim_end_matches(' ').len())
15968                        .collect::<SmallVec<[usize; 4]>>();
15969
15970                    let mut all_selection_lines_are_comments = true;
15971
15972                    for row in start_row.0..=end_row.0 {
15973                        let row = MultiBufferRow(row);
15974                        if start_row < end_row && snapshot.is_line_blank(row) {
15975                            continue;
15976                        }
15977
15978                        let prefix_range = full_comment_prefixes
15979                            .iter()
15980                            .zip(prefix_trimmed_lengths.iter().copied())
15981                            .map(|(prefix, trimmed_prefix_len)| {
15982                                comment_prefix_range(
15983                                    snapshot.deref(),
15984                                    row,
15985                                    &prefix[..trimmed_prefix_len],
15986                                    &prefix[trimmed_prefix_len..],
15987                                    ignore_indent,
15988                                )
15989                            })
15990                            .max_by_key(|range| range.end.column - range.start.column)
15991                            .expect("prefixes is non-empty");
15992
15993                        if prefix_range.is_empty() {
15994                            all_selection_lines_are_comments = false;
15995                        }
15996
15997                        selection_edit_ranges.push(prefix_range);
15998                    }
15999
16000                    if all_selection_lines_are_comments {
16001                        edits.extend(
16002                            selection_edit_ranges
16003                                .iter()
16004                                .cloned()
16005                                .map(|range| (range, empty_str.clone())),
16006                        );
16007                    } else {
16008                        let min_column = selection_edit_ranges
16009                            .iter()
16010                            .map(|range| range.start.column)
16011                            .min()
16012                            .unwrap_or(0);
16013                        edits.extend(selection_edit_ranges.iter().map(|range| {
16014                            let position = Point::new(range.start.row, min_column);
16015                            (position..position, first_prefix.clone())
16016                        }));
16017                    }
16018                } else if let Some(BlockCommentConfig {
16019                    start: full_comment_prefix,
16020                    end: comment_suffix,
16021                    ..
16022                }) = language.block_comment()
16023                {
16024                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
16025                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
16026                    let prefix_range = comment_prefix_range(
16027                        snapshot.deref(),
16028                        start_row,
16029                        comment_prefix,
16030                        comment_prefix_whitespace,
16031                        ignore_indent,
16032                    );
16033                    let suffix_range = comment_suffix_range(
16034                        snapshot.deref(),
16035                        end_row,
16036                        comment_suffix.trim_start_matches(' '),
16037                        comment_suffix.starts_with(' '),
16038                    );
16039
16040                    if prefix_range.is_empty() || suffix_range.is_empty() {
16041                        edits.push((
16042                            prefix_range.start..prefix_range.start,
16043                            full_comment_prefix.clone(),
16044                        ));
16045                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
16046                        suffixes_inserted.push((end_row, comment_suffix.len()));
16047                    } else {
16048                        edits.push((prefix_range, empty_str.clone()));
16049                        edits.push((suffix_range, empty_str.clone()));
16050                    }
16051                } else {
16052                    continue;
16053                }
16054            }
16055
16056            drop(snapshot);
16057            this.buffer.update(cx, |buffer, cx| {
16058                buffer.edit(edits, None, cx);
16059            });
16060
16061            // Adjust selections so that they end before any comment suffixes that
16062            // were inserted.
16063            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
16064            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16065            let snapshot = this.buffer.read(cx).read(cx);
16066            for selection in &mut selections {
16067                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
16068                    match row.cmp(&MultiBufferRow(selection.end.row)) {
16069                        Ordering::Less => {
16070                            suffixes_inserted.next();
16071                            continue;
16072                        }
16073                        Ordering::Greater => break,
16074                        Ordering::Equal => {
16075                            if selection.end.column == snapshot.line_len(row) {
16076                                if selection.is_empty() {
16077                                    selection.start.column -= suffix_len as u32;
16078                                }
16079                                selection.end.column -= suffix_len as u32;
16080                            }
16081                            break;
16082                        }
16083                    }
16084                }
16085            }
16086
16087            drop(snapshot);
16088            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
16089
16090            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16091            let selections_on_single_row = selections.windows(2).all(|selections| {
16092                selections[0].start.row == selections[1].start.row
16093                    && selections[0].end.row == selections[1].end.row
16094                    && selections[0].start.row == selections[0].end.row
16095            });
16096            let selections_selecting = selections
16097                .iter()
16098                .any(|selection| selection.start != selection.end);
16099            let advance_downwards = action.advance_downwards
16100                && selections_on_single_row
16101                && !selections_selecting
16102                && !matches!(this.mode, EditorMode::SingleLine);
16103
16104            if advance_downwards {
16105                let snapshot = this.buffer.read(cx).snapshot(cx);
16106
16107                this.change_selections(Default::default(), window, cx, |s| {
16108                    s.move_cursors_with(|display_snapshot, display_point, _| {
16109                        let mut point = display_point.to_point(display_snapshot);
16110                        point.row += 1;
16111                        point = snapshot.clip_point(point, Bias::Left);
16112                        let display_point = point.to_display_point(display_snapshot);
16113                        let goal = SelectionGoal::HorizontalPosition(
16114                            display_snapshot
16115                                .x_for_display_point(display_point, text_layout_details)
16116                                .into(),
16117                        );
16118                        (display_point, goal)
16119                    })
16120                });
16121            }
16122        });
16123    }
16124
16125    pub fn select_enclosing_symbol(
16126        &mut self,
16127        _: &SelectEnclosingSymbol,
16128        window: &mut Window,
16129        cx: &mut Context<Self>,
16130    ) {
16131        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16132
16133        let buffer = self.buffer.read(cx).snapshot(cx);
16134        let old_selections = self
16135            .selections
16136            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16137            .into_boxed_slice();
16138
16139        fn update_selection(
16140            selection: &Selection<MultiBufferOffset>,
16141            buffer_snap: &MultiBufferSnapshot,
16142        ) -> Option<Selection<MultiBufferOffset>> {
16143            let cursor = selection.head();
16144            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
16145            for symbol in symbols.iter().rev() {
16146                let start = symbol.range.start.to_offset(buffer_snap);
16147                let end = symbol.range.end.to_offset(buffer_snap);
16148                let new_range = start..end;
16149                if start < selection.start || end > selection.end {
16150                    return Some(Selection {
16151                        id: selection.id,
16152                        start: new_range.start,
16153                        end: new_range.end,
16154                        goal: SelectionGoal::None,
16155                        reversed: selection.reversed,
16156                    });
16157                }
16158            }
16159            None
16160        }
16161
16162        let mut selected_larger_symbol = false;
16163        let new_selections = old_selections
16164            .iter()
16165            .map(|selection| match update_selection(selection, &buffer) {
16166                Some(new_selection) => {
16167                    if new_selection.range() != selection.range() {
16168                        selected_larger_symbol = true;
16169                    }
16170                    new_selection
16171                }
16172                None => selection.clone(),
16173            })
16174            .collect::<Vec<_>>();
16175
16176        if selected_larger_symbol {
16177            self.change_selections(Default::default(), window, cx, |s| {
16178                s.select(new_selections);
16179            });
16180        }
16181    }
16182
16183    pub fn select_larger_syntax_node(
16184        &mut self,
16185        _: &SelectLargerSyntaxNode,
16186        window: &mut Window,
16187        cx: &mut Context<Self>,
16188    ) {
16189        let Some(visible_row_count) = self.visible_row_count() else {
16190            return;
16191        };
16192        let old_selections: Box<[_]> = self
16193            .selections
16194            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16195            .into();
16196        if old_selections.is_empty() {
16197            return;
16198        }
16199
16200        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16201
16202        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16203        let buffer = self.buffer.read(cx).snapshot(cx);
16204
16205        let mut selected_larger_node = false;
16206        let mut new_selections = old_selections
16207            .iter()
16208            .map(|selection| {
16209                let old_range = selection.start..selection.end;
16210
16211                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
16212                    // manually select word at selection
16213                    if ["string_content", "inline"].contains(&node.kind()) {
16214                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
16215                        // ignore if word is already selected
16216                        if !word_range.is_empty() && old_range != word_range {
16217                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16218                            // only select word if start and end point belongs to same word
16219                            if word_range == last_word_range {
16220                                selected_larger_node = true;
16221                                return Selection {
16222                                    id: selection.id,
16223                                    start: word_range.start,
16224                                    end: word_range.end,
16225                                    goal: SelectionGoal::None,
16226                                    reversed: selection.reversed,
16227                                };
16228                            }
16229                        }
16230                    }
16231                }
16232
16233                let mut new_range = old_range.clone();
16234                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16235                    new_range = range;
16236                    if !node.is_named() {
16237                        continue;
16238                    }
16239                    if !display_map.intersects_fold(new_range.start)
16240                        && !display_map.intersects_fold(new_range.end)
16241                    {
16242                        break;
16243                    }
16244                }
16245
16246                selected_larger_node |= new_range != old_range;
16247                Selection {
16248                    id: selection.id,
16249                    start: new_range.start,
16250                    end: new_range.end,
16251                    goal: SelectionGoal::None,
16252                    reversed: selection.reversed,
16253                }
16254            })
16255            .collect::<Vec<_>>();
16256
16257        if !selected_larger_node {
16258            return; // don't put this call in the history
16259        }
16260
16261        // scroll based on transformation done to the last selection created by the user
16262        let (last_old, last_new) = old_selections
16263            .last()
16264            .zip(new_selections.last().cloned())
16265            .expect("old_selections isn't empty");
16266
16267        // revert selection
16268        let is_selection_reversed = {
16269            let should_newest_selection_be_reversed = last_old.start != last_new.start;
16270            new_selections.last_mut().expect("checked above").reversed =
16271                should_newest_selection_be_reversed;
16272            should_newest_selection_be_reversed
16273        };
16274
16275        if selected_larger_node {
16276            self.select_syntax_node_history.disable_clearing = true;
16277            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16278                s.select(new_selections.clone());
16279            });
16280            self.select_syntax_node_history.disable_clearing = false;
16281        }
16282
16283        let start_row = last_new.start.to_display_point(&display_map).row().0;
16284        let end_row = last_new.end.to_display_point(&display_map).row().0;
16285        let selection_height = end_row - start_row + 1;
16286        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16287
16288        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16289        let scroll_behavior = if fits_on_the_screen {
16290            self.request_autoscroll(Autoscroll::fit(), cx);
16291            SelectSyntaxNodeScrollBehavior::FitSelection
16292        } else if is_selection_reversed {
16293            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16294            SelectSyntaxNodeScrollBehavior::CursorTop
16295        } else {
16296            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16297            SelectSyntaxNodeScrollBehavior::CursorBottom
16298        };
16299
16300        self.select_syntax_node_history.push((
16301            old_selections,
16302            scroll_behavior,
16303            is_selection_reversed,
16304        ));
16305    }
16306
16307    pub fn select_smaller_syntax_node(
16308        &mut self,
16309        _: &SelectSmallerSyntaxNode,
16310        window: &mut Window,
16311        cx: &mut Context<Self>,
16312    ) {
16313        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16314
16315        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16316            self.select_syntax_node_history.pop()
16317        {
16318            if let Some(selection) = selections.last_mut() {
16319                selection.reversed = is_selection_reversed;
16320            }
16321
16322            self.select_syntax_node_history.disable_clearing = true;
16323            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16324                s.select(selections.to_vec());
16325            });
16326            self.select_syntax_node_history.disable_clearing = false;
16327
16328            match scroll_behavior {
16329                SelectSyntaxNodeScrollBehavior::CursorTop => {
16330                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16331                }
16332                SelectSyntaxNodeScrollBehavior::FitSelection => {
16333                    self.request_autoscroll(Autoscroll::fit(), cx);
16334                }
16335                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16336                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16337                }
16338            }
16339        }
16340    }
16341
16342    pub fn unwrap_syntax_node(
16343        &mut self,
16344        _: &UnwrapSyntaxNode,
16345        window: &mut Window,
16346        cx: &mut Context<Self>,
16347    ) {
16348        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16349
16350        let buffer = self.buffer.read(cx).snapshot(cx);
16351        let selections = self
16352            .selections
16353            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16354            .into_iter()
16355            // subtracting the offset requires sorting
16356            .sorted_by_key(|i| i.start);
16357
16358        let full_edits = selections
16359            .into_iter()
16360            .filter_map(|selection| {
16361                let child = if selection.is_empty()
16362                    && let Some((_, ancestor_range)) =
16363                        buffer.syntax_ancestor(selection.start..selection.end)
16364                {
16365                    ancestor_range
16366                } else {
16367                    selection.range()
16368                };
16369
16370                let mut parent = child.clone();
16371                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16372                    parent = ancestor_range;
16373                    if parent.start < child.start || parent.end > child.end {
16374                        break;
16375                    }
16376                }
16377
16378                if parent == child {
16379                    return None;
16380                }
16381                let text = buffer.text_for_range(child).collect::<String>();
16382                Some((selection.id, parent, text))
16383            })
16384            .collect::<Vec<_>>();
16385        if full_edits.is_empty() {
16386            return;
16387        }
16388
16389        self.transact(window, cx, |this, window, cx| {
16390            this.buffer.update(cx, |buffer, cx| {
16391                buffer.edit(
16392                    full_edits
16393                        .iter()
16394                        .map(|(_, p, t)| (p.clone(), t.clone()))
16395                        .collect::<Vec<_>>(),
16396                    None,
16397                    cx,
16398                );
16399            });
16400            this.change_selections(Default::default(), window, cx, |s| {
16401                let mut offset = 0;
16402                let mut selections = vec![];
16403                for (id, parent, text) in full_edits {
16404                    let start = parent.start - offset;
16405                    offset += (parent.end - parent.start) - text.len();
16406                    selections.push(Selection {
16407                        id,
16408                        start,
16409                        end: start + text.len(),
16410                        reversed: false,
16411                        goal: Default::default(),
16412                    });
16413                }
16414                s.select(selections);
16415            });
16416        });
16417    }
16418
16419    pub fn select_next_syntax_node(
16420        &mut self,
16421        _: &SelectNextSyntaxNode,
16422        window: &mut Window,
16423        cx: &mut Context<Self>,
16424    ) {
16425        let old_selections: Box<[_]> = self
16426            .selections
16427            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16428            .into();
16429        if old_selections.is_empty() {
16430            return;
16431        }
16432
16433        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16434
16435        let buffer = self.buffer.read(cx).snapshot(cx);
16436        let mut selected_sibling = false;
16437
16438        let new_selections = old_selections
16439            .iter()
16440            .map(|selection| {
16441                let old_range = selection.start..selection.end;
16442
16443                let old_range =
16444                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16445                let excerpt = buffer.excerpt_containing(old_range.clone());
16446
16447                if let Some(mut excerpt) = excerpt
16448                    && let Some(node) = excerpt
16449                        .buffer()
16450                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16451                {
16452                    let new_range = excerpt.map_range_from_buffer(
16453                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16454                    );
16455                    selected_sibling = true;
16456                    Selection {
16457                        id: selection.id,
16458                        start: new_range.start,
16459                        end: new_range.end,
16460                        goal: SelectionGoal::None,
16461                        reversed: selection.reversed,
16462                    }
16463                } else {
16464                    selection.clone()
16465                }
16466            })
16467            .collect::<Vec<_>>();
16468
16469        if selected_sibling {
16470            self.change_selections(
16471                SelectionEffects::scroll(Autoscroll::fit()),
16472                window,
16473                cx,
16474                |s| {
16475                    s.select(new_selections);
16476                },
16477            );
16478        }
16479    }
16480
16481    pub fn select_prev_syntax_node(
16482        &mut self,
16483        _: &SelectPreviousSyntaxNode,
16484        window: &mut Window,
16485        cx: &mut Context<Self>,
16486    ) {
16487        let old_selections: Box<[_]> = self
16488            .selections
16489            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16490            .into();
16491        if old_selections.is_empty() {
16492            return;
16493        }
16494
16495        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16496
16497        let buffer = self.buffer.read(cx).snapshot(cx);
16498        let mut selected_sibling = false;
16499
16500        let new_selections = old_selections
16501            .iter()
16502            .map(|selection| {
16503                let old_range = selection.start..selection.end;
16504                let old_range =
16505                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16506                let excerpt = buffer.excerpt_containing(old_range.clone());
16507
16508                if let Some(mut excerpt) = excerpt
16509                    && let Some(node) = excerpt
16510                        .buffer()
16511                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16512                {
16513                    let new_range = excerpt.map_range_from_buffer(
16514                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16515                    );
16516                    selected_sibling = true;
16517                    Selection {
16518                        id: selection.id,
16519                        start: new_range.start,
16520                        end: new_range.end,
16521                        goal: SelectionGoal::None,
16522                        reversed: selection.reversed,
16523                    }
16524                } else {
16525                    selection.clone()
16526                }
16527            })
16528            .collect::<Vec<_>>();
16529
16530        if selected_sibling {
16531            self.change_selections(
16532                SelectionEffects::scroll(Autoscroll::fit()),
16533                window,
16534                cx,
16535                |s| {
16536                    s.select(new_selections);
16537                },
16538            );
16539        }
16540    }
16541
16542    pub fn move_to_start_of_larger_syntax_node(
16543        &mut self,
16544        _: &MoveToStartOfLargerSyntaxNode,
16545        window: &mut Window,
16546        cx: &mut Context<Self>,
16547    ) {
16548        self.move_cursors_to_syntax_nodes(window, cx, false);
16549    }
16550
16551    pub fn move_to_end_of_larger_syntax_node(
16552        &mut self,
16553        _: &MoveToEndOfLargerSyntaxNode,
16554        window: &mut Window,
16555        cx: &mut Context<Self>,
16556    ) {
16557        self.move_cursors_to_syntax_nodes(window, cx, true);
16558    }
16559
16560    fn move_cursors_to_syntax_nodes(
16561        &mut self,
16562        window: &mut Window,
16563        cx: &mut Context<Self>,
16564        move_to_end: bool,
16565    ) -> bool {
16566        let old_selections: Box<[_]> = self
16567            .selections
16568            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16569            .into();
16570        if old_selections.is_empty() {
16571            return false;
16572        }
16573
16574        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16575
16576        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16577        let buffer = self.buffer.read(cx).snapshot(cx);
16578
16579        let mut any_cursor_moved = false;
16580        let new_selections = old_selections
16581            .iter()
16582            .map(|selection| {
16583                if !selection.is_empty() {
16584                    return selection.clone();
16585                }
16586
16587                let selection_pos = selection.head();
16588                let old_range = selection_pos..selection_pos;
16589
16590                let mut new_pos = selection_pos;
16591                let mut search_range = old_range;
16592                while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
16593                    search_range = range.clone();
16594                    if !node.is_named()
16595                        || display_map.intersects_fold(range.start)
16596                        || display_map.intersects_fold(range.end)
16597                        // If cursor is already at the end of the syntax node, continue searching
16598                        || (move_to_end && range.end == selection_pos)
16599                        // If cursor is already at the start of the syntax node, continue searching
16600                        || (!move_to_end && range.start == selection_pos)
16601                    {
16602                        continue;
16603                    }
16604
16605                    // If we found a string_content node, find the largest parent that is still string_content
16606                    // Enables us to skip to the end of strings without taking multiple steps inside the string
16607                    let (_, final_range) = if node.kind() == "string_content" {
16608                        let mut current_node = node;
16609                        let mut current_range = range;
16610                        while let Some((parent, parent_range)) =
16611                            buffer.syntax_ancestor(current_range.clone())
16612                        {
16613                            if parent.kind() == "string_content" {
16614                                current_node = parent;
16615                                current_range = parent_range;
16616                            } else {
16617                                break;
16618                            }
16619                        }
16620
16621                        (current_node, current_range)
16622                    } else {
16623                        (node, range)
16624                    };
16625
16626                    new_pos = if move_to_end {
16627                        final_range.end
16628                    } else {
16629                        final_range.start
16630                    };
16631
16632                    break;
16633                }
16634
16635                any_cursor_moved |= new_pos != selection_pos;
16636
16637                Selection {
16638                    id: selection.id,
16639                    start: new_pos,
16640                    end: new_pos,
16641                    goal: SelectionGoal::None,
16642                    reversed: false,
16643                }
16644            })
16645            .collect::<Vec<_>>();
16646
16647        self.change_selections(Default::default(), window, cx, |s| {
16648            s.select(new_selections);
16649        });
16650        self.request_autoscroll(Autoscroll::newest(), cx);
16651
16652        any_cursor_moved
16653    }
16654
16655    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16656        if !EditorSettings::get_global(cx).gutter.runnables {
16657            self.clear_tasks();
16658            return Task::ready(());
16659        }
16660        let project = self.project().map(Entity::downgrade);
16661        let task_sources = self.lsp_task_sources(cx);
16662        let multi_buffer = self.buffer.downgrade();
16663        cx.spawn_in(window, async move |editor, cx| {
16664            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16665            let Some(project) = project.and_then(|p| p.upgrade()) else {
16666                return;
16667            };
16668            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16669                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16670            }) else {
16671                return;
16672            };
16673
16674            let hide_runnables = project.update(cx, |project, _| project.is_via_collab());
16675            if hide_runnables {
16676                return;
16677            }
16678            let new_rows =
16679                cx.background_spawn({
16680                    let snapshot = display_snapshot.clone();
16681                    async move {
16682                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16683                    }
16684                })
16685                    .await;
16686            let Ok(lsp_tasks) =
16687                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16688            else {
16689                return;
16690            };
16691            let lsp_tasks = lsp_tasks.await;
16692
16693            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16694                lsp_tasks
16695                    .into_iter()
16696                    .flat_map(|(kind, tasks)| {
16697                        tasks.into_iter().filter_map(move |(location, task)| {
16698                            Some((kind.clone(), location?, task))
16699                        })
16700                    })
16701                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16702                        let buffer = location.target.buffer;
16703                        let buffer_snapshot = buffer.read(cx).snapshot();
16704                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16705                            |(excerpt_id, snapshot, _)| {
16706                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16707                                    display_snapshot
16708                                        .buffer_snapshot()
16709                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16710                                } else {
16711                                    None
16712                                }
16713                            },
16714                        );
16715                        if let Some(offset) = offset {
16716                            let task_buffer_range =
16717                                location.target.range.to_point(&buffer_snapshot);
16718                            let context_buffer_range =
16719                                task_buffer_range.to_offset(&buffer_snapshot);
16720                            let context_range = BufferOffset(context_buffer_range.start)
16721                                ..BufferOffset(context_buffer_range.end);
16722
16723                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16724                                .or_insert_with(|| RunnableTasks {
16725                                    templates: Vec::new(),
16726                                    offset,
16727                                    column: task_buffer_range.start.column,
16728                                    extra_variables: HashMap::default(),
16729                                    context_range,
16730                                })
16731                                .templates
16732                                .push((kind, task.original_task().clone()));
16733                        }
16734
16735                        acc
16736                    })
16737            }) else {
16738                return;
16739            };
16740
16741            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16742                buffer.language_settings(cx).tasks.prefer_lsp
16743            }) else {
16744                return;
16745            };
16746
16747            let rows = Self::runnable_rows(
16748                project,
16749                display_snapshot,
16750                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16751                new_rows,
16752                cx.clone(),
16753            )
16754            .await;
16755            editor
16756                .update(cx, |editor, _| {
16757                    editor.clear_tasks();
16758                    for (key, mut value) in rows {
16759                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16760                            value.templates.extend(lsp_tasks.templates);
16761                        }
16762
16763                        editor.insert_tasks(key, value);
16764                    }
16765                    for (key, value) in lsp_tasks_by_rows {
16766                        editor.insert_tasks(key, value);
16767                    }
16768                })
16769                .ok();
16770        })
16771    }
16772    fn fetch_runnable_ranges(
16773        snapshot: &DisplaySnapshot,
16774        range: Range<Anchor>,
16775    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16776        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16777    }
16778
16779    fn runnable_rows(
16780        project: Entity<Project>,
16781        snapshot: DisplaySnapshot,
16782        prefer_lsp: bool,
16783        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16784        cx: AsyncWindowContext,
16785    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16786        cx.spawn(async move |cx| {
16787            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16788            for (run_range, mut runnable) in runnable_ranges {
16789                let Some(tasks) = cx
16790                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16791                    .ok()
16792                else {
16793                    continue;
16794                };
16795                let mut tasks = tasks.await;
16796
16797                if prefer_lsp {
16798                    tasks.retain(|(task_kind, _)| {
16799                        !matches!(task_kind, TaskSourceKind::Language { .. })
16800                    });
16801                }
16802                if tasks.is_empty() {
16803                    continue;
16804                }
16805
16806                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16807                let Some(row) = snapshot
16808                    .buffer_snapshot()
16809                    .buffer_line_for_row(MultiBufferRow(point.row))
16810                    .map(|(_, range)| range.start.row)
16811                else {
16812                    continue;
16813                };
16814
16815                let context_range =
16816                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16817                runnable_rows.push((
16818                    (runnable.buffer_id, row),
16819                    RunnableTasks {
16820                        templates: tasks,
16821                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16822                        context_range,
16823                        column: point.column,
16824                        extra_variables: runnable.extra_captures,
16825                    },
16826                ));
16827            }
16828            runnable_rows
16829        })
16830    }
16831
16832    fn templates_with_tags(
16833        project: &Entity<Project>,
16834        runnable: &mut Runnable,
16835        cx: &mut App,
16836    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16837        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16838            let (worktree_id, file) = project
16839                .buffer_for_id(runnable.buffer, cx)
16840                .and_then(|buffer| buffer.read(cx).file())
16841                .map(|file| (file.worktree_id(cx), file.clone()))
16842                .unzip();
16843
16844            (
16845                project.task_store().read(cx).task_inventory().cloned(),
16846                worktree_id,
16847                file,
16848            )
16849        });
16850
16851        let tags = mem::take(&mut runnable.tags);
16852        let language = runnable.language.clone();
16853        cx.spawn(async move |cx| {
16854            let mut templates_with_tags = Vec::new();
16855            if let Some(inventory) = inventory {
16856                for RunnableTag(tag) in tags {
16857                    let new_tasks = inventory.update(cx, |inventory, cx| {
16858                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16859                    });
16860                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16861                        move |(_, template)| {
16862                            template.tags.iter().any(|source_tag| source_tag == &tag)
16863                        },
16864                    ));
16865                }
16866            }
16867            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16868
16869            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16870                // Strongest source wins; if we have worktree tag binding, prefer that to
16871                // global and language bindings;
16872                // if we have a global binding, prefer that to language binding.
16873                let first_mismatch = templates_with_tags
16874                    .iter()
16875                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16876                if let Some(index) = first_mismatch {
16877                    templates_with_tags.truncate(index);
16878                }
16879            }
16880
16881            templates_with_tags
16882        })
16883    }
16884
16885    pub fn move_to_enclosing_bracket(
16886        &mut self,
16887        _: &MoveToEnclosingBracket,
16888        window: &mut Window,
16889        cx: &mut Context<Self>,
16890    ) {
16891        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16892        self.change_selections(Default::default(), window, cx, |s| {
16893            s.move_offsets_with(|snapshot, selection| {
16894                let Some(enclosing_bracket_ranges) =
16895                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16896                else {
16897                    return;
16898                };
16899
16900                let mut best_length = usize::MAX;
16901                let mut best_inside = false;
16902                let mut best_in_bracket_range = false;
16903                let mut best_destination = None;
16904                for (open, close) in enclosing_bracket_ranges {
16905                    let close = close.to_inclusive();
16906                    let length = *close.end() - open.start;
16907                    let inside = selection.start >= open.end && selection.end <= *close.start();
16908                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16909                        || close.contains(&selection.head());
16910
16911                    // If best is next to a bracket and current isn't, skip
16912                    if !in_bracket_range && best_in_bracket_range {
16913                        continue;
16914                    }
16915
16916                    // Prefer smaller lengths unless best is inside and current isn't
16917                    if length > best_length && (best_inside || !inside) {
16918                        continue;
16919                    }
16920
16921                    best_length = length;
16922                    best_inside = inside;
16923                    best_in_bracket_range = in_bracket_range;
16924                    best_destination = Some(
16925                        if close.contains(&selection.start) && close.contains(&selection.end) {
16926                            if inside { open.end } else { open.start }
16927                        } else if inside {
16928                            *close.start()
16929                        } else {
16930                            *close.end()
16931                        },
16932                    );
16933                }
16934
16935                if let Some(destination) = best_destination {
16936                    selection.collapse_to(destination, SelectionGoal::None);
16937                }
16938            })
16939        });
16940    }
16941
16942    pub fn undo_selection(
16943        &mut self,
16944        _: &UndoSelection,
16945        window: &mut Window,
16946        cx: &mut Context<Self>,
16947    ) {
16948        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16949        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16950            self.selection_history.mode = SelectionHistoryMode::Undoing;
16951            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16952                this.end_selection(window, cx);
16953                this.change_selections(
16954                    SelectionEffects::scroll(Autoscroll::newest()),
16955                    window,
16956                    cx,
16957                    |s| s.select_anchors(entry.selections.to_vec()),
16958                );
16959            });
16960            self.selection_history.mode = SelectionHistoryMode::Normal;
16961
16962            self.select_next_state = entry.select_next_state;
16963            self.select_prev_state = entry.select_prev_state;
16964            self.add_selections_state = entry.add_selections_state;
16965        }
16966    }
16967
16968    pub fn redo_selection(
16969        &mut self,
16970        _: &RedoSelection,
16971        window: &mut Window,
16972        cx: &mut Context<Self>,
16973    ) {
16974        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16975        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16976            self.selection_history.mode = SelectionHistoryMode::Redoing;
16977            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16978                this.end_selection(window, cx);
16979                this.change_selections(
16980                    SelectionEffects::scroll(Autoscroll::newest()),
16981                    window,
16982                    cx,
16983                    |s| s.select_anchors(entry.selections.to_vec()),
16984                );
16985            });
16986            self.selection_history.mode = SelectionHistoryMode::Normal;
16987
16988            self.select_next_state = entry.select_next_state;
16989            self.select_prev_state = entry.select_prev_state;
16990            self.add_selections_state = entry.add_selections_state;
16991        }
16992    }
16993
16994    pub fn expand_excerpts(
16995        &mut self,
16996        action: &ExpandExcerpts,
16997        _: &mut Window,
16998        cx: &mut Context<Self>,
16999    ) {
17000        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
17001    }
17002
17003    pub fn expand_excerpts_down(
17004        &mut self,
17005        action: &ExpandExcerptsDown,
17006        _: &mut Window,
17007        cx: &mut Context<Self>,
17008    ) {
17009        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
17010    }
17011
17012    pub fn expand_excerpts_up(
17013        &mut self,
17014        action: &ExpandExcerptsUp,
17015        _: &mut Window,
17016        cx: &mut Context<Self>,
17017    ) {
17018        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
17019    }
17020
17021    pub fn expand_excerpts_for_direction(
17022        &mut self,
17023        lines: u32,
17024        direction: ExpandExcerptDirection,
17025        cx: &mut Context<Self>,
17026    ) {
17027        let selections = self.selections.disjoint_anchors_arc();
17028
17029        let lines = if lines == 0 {
17030            EditorSettings::get_global(cx).expand_excerpt_lines
17031        } else {
17032            lines
17033        };
17034
17035        let snapshot = self.buffer.read(cx).snapshot(cx);
17036        let mut excerpt_ids = selections
17037            .iter()
17038            .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
17039            .collect::<Vec<_>>();
17040        excerpt_ids.sort();
17041        excerpt_ids.dedup();
17042
17043        if self.delegate_expand_excerpts {
17044            cx.emit(EditorEvent::ExpandExcerptsRequested {
17045                excerpt_ids,
17046                lines,
17047                direction,
17048            });
17049            return;
17050        }
17051
17052        self.buffer.update(cx, |buffer, cx| {
17053            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
17054        })
17055    }
17056
17057    pub fn expand_excerpt(
17058        &mut self,
17059        excerpt: ExcerptId,
17060        direction: ExpandExcerptDirection,
17061        window: &mut Window,
17062        cx: &mut Context<Self>,
17063    ) {
17064        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
17065
17066        if self.delegate_expand_excerpts {
17067            cx.emit(EditorEvent::ExpandExcerptsRequested {
17068                excerpt_ids: vec![excerpt],
17069                lines: lines_to_expand,
17070                direction,
17071            });
17072            return;
17073        }
17074
17075        let current_scroll_position = self.scroll_position(cx);
17076        let mut scroll = None;
17077
17078        if direction == ExpandExcerptDirection::Down {
17079            let multi_buffer = self.buffer.read(cx);
17080            let snapshot = multi_buffer.snapshot(cx);
17081            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
17082                && let Some(buffer) = multi_buffer.buffer(buffer_id)
17083                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
17084            {
17085                let buffer_snapshot = buffer.read(cx).snapshot();
17086                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
17087                let last_row = buffer_snapshot.max_point().row;
17088                let lines_below = last_row.saturating_sub(excerpt_end_row);
17089                if lines_below >= lines_to_expand {
17090                    scroll = Some(
17091                        current_scroll_position
17092                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
17093                    );
17094                }
17095            }
17096        }
17097        if direction == ExpandExcerptDirection::Up
17098            && self
17099                .buffer
17100                .read(cx)
17101                .snapshot(cx)
17102                .excerpt_before(excerpt)
17103                .is_none()
17104        {
17105            scroll = Some(current_scroll_position);
17106        }
17107
17108        self.buffer.update(cx, |buffer, cx| {
17109            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
17110        });
17111
17112        if let Some(new_scroll_position) = scroll {
17113            self.set_scroll_position(new_scroll_position, window, cx);
17114        }
17115    }
17116
17117    pub fn go_to_singleton_buffer_point(
17118        &mut self,
17119        point: Point,
17120        window: &mut Window,
17121        cx: &mut Context<Self>,
17122    ) {
17123        self.go_to_singleton_buffer_range(point..point, window, cx);
17124    }
17125
17126    pub fn go_to_singleton_buffer_range(
17127        &mut self,
17128        range: Range<Point>,
17129        window: &mut Window,
17130        cx: &mut Context<Self>,
17131    ) {
17132        let multibuffer = self.buffer().read(cx);
17133        let Some(buffer) = multibuffer.as_singleton() else {
17134            return;
17135        };
17136        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
17137            return;
17138        };
17139        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
17140            return;
17141        };
17142        self.change_selections(
17143            SelectionEffects::default().nav_history(true),
17144            window,
17145            cx,
17146            |s| s.select_anchor_ranges([start..end]),
17147        );
17148    }
17149
17150    pub fn go_to_diagnostic(
17151        &mut self,
17152        action: &GoToDiagnostic,
17153        window: &mut Window,
17154        cx: &mut Context<Self>,
17155    ) {
17156        if !self.diagnostics_enabled() {
17157            return;
17158        }
17159        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17160        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
17161    }
17162
17163    pub fn go_to_prev_diagnostic(
17164        &mut self,
17165        action: &GoToPreviousDiagnostic,
17166        window: &mut Window,
17167        cx: &mut Context<Self>,
17168    ) {
17169        if !self.diagnostics_enabled() {
17170            return;
17171        }
17172        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17173        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
17174    }
17175
17176    pub fn go_to_diagnostic_impl(
17177        &mut self,
17178        direction: Direction,
17179        severity: GoToDiagnosticSeverityFilter,
17180        window: &mut Window,
17181        cx: &mut Context<Self>,
17182    ) {
17183        let buffer = self.buffer.read(cx).snapshot(cx);
17184        let selection = self
17185            .selections
17186            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17187
17188        let mut active_group_id = None;
17189        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
17190            && active_group.active_range.start.to_offset(&buffer) == selection.start
17191        {
17192            active_group_id = Some(active_group.group_id);
17193        }
17194
17195        fn filtered<'a>(
17196            severity: GoToDiagnosticSeverityFilter,
17197            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
17198        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
17199            diagnostics
17200                .filter(move |entry| severity.matches(entry.diagnostic.severity))
17201                .filter(|entry| entry.range.start != entry.range.end)
17202                .filter(|entry| !entry.diagnostic.is_unnecessary)
17203        }
17204
17205        let before = filtered(
17206            severity,
17207            buffer
17208                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
17209                .filter(|entry| entry.range.start <= selection.start),
17210        );
17211        let after = filtered(
17212            severity,
17213            buffer
17214                .diagnostics_in_range(selection.start..buffer.len())
17215                .filter(|entry| entry.range.start >= selection.start),
17216        );
17217
17218        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
17219        if direction == Direction::Prev {
17220            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
17221            {
17222                for diagnostic in prev_diagnostics.into_iter().rev() {
17223                    if diagnostic.range.start != selection.start
17224                        || active_group_id
17225                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
17226                    {
17227                        found = Some(diagnostic);
17228                        break 'outer;
17229                    }
17230                }
17231            }
17232        } else {
17233            for diagnostic in after.chain(before) {
17234                if diagnostic.range.start != selection.start
17235                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
17236                {
17237                    found = Some(diagnostic);
17238                    break;
17239                }
17240            }
17241        }
17242        let Some(next_diagnostic) = found else {
17243            return;
17244        };
17245
17246        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
17247        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
17248            return;
17249        };
17250        let snapshot = self.snapshot(window, cx);
17251        if snapshot.intersects_fold(next_diagnostic.range.start) {
17252            self.unfold_ranges(
17253                std::slice::from_ref(&next_diagnostic.range),
17254                true,
17255                false,
17256                cx,
17257            );
17258        }
17259        self.change_selections(Default::default(), window, cx, |s| {
17260            s.select_ranges(vec![
17261                next_diagnostic.range.start..next_diagnostic.range.start,
17262            ])
17263        });
17264        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
17265        self.refresh_edit_prediction(false, true, window, cx);
17266    }
17267
17268    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
17269        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17270        let snapshot = self.snapshot(window, cx);
17271        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17272        self.go_to_hunk_before_or_after_position(
17273            &snapshot,
17274            selection.head(),
17275            Direction::Next,
17276            window,
17277            cx,
17278        );
17279    }
17280
17281    pub fn go_to_hunk_before_or_after_position(
17282        &mut self,
17283        snapshot: &EditorSnapshot,
17284        position: Point,
17285        direction: Direction,
17286        window: &mut Window,
17287        cx: &mut Context<Editor>,
17288    ) {
17289        let row = if direction == Direction::Next {
17290            self.hunk_after_position(snapshot, position)
17291                .map(|hunk| hunk.row_range.start)
17292        } else {
17293            self.hunk_before_position(snapshot, position)
17294        };
17295
17296        if let Some(row) = row {
17297            let destination = Point::new(row.0, 0);
17298            let autoscroll = Autoscroll::center();
17299
17300            self.unfold_ranges(&[destination..destination], false, false, cx);
17301            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17302                s.select_ranges([destination..destination]);
17303            });
17304        }
17305    }
17306
17307    fn hunk_after_position(
17308        &mut self,
17309        snapshot: &EditorSnapshot,
17310        position: Point,
17311    ) -> Option<MultiBufferDiffHunk> {
17312        snapshot
17313            .buffer_snapshot()
17314            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
17315            .find(|hunk| hunk.row_range.start.0 > position.row)
17316            .or_else(|| {
17317                snapshot
17318                    .buffer_snapshot()
17319                    .diff_hunks_in_range(Point::zero()..position)
17320                    .find(|hunk| hunk.row_range.end.0 < position.row)
17321            })
17322    }
17323
17324    fn go_to_prev_hunk(
17325        &mut self,
17326        _: &GoToPreviousHunk,
17327        window: &mut Window,
17328        cx: &mut Context<Self>,
17329    ) {
17330        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17331        let snapshot = self.snapshot(window, cx);
17332        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17333        self.go_to_hunk_before_or_after_position(
17334            &snapshot,
17335            selection.head(),
17336            Direction::Prev,
17337            window,
17338            cx,
17339        );
17340    }
17341
17342    fn hunk_before_position(
17343        &mut self,
17344        snapshot: &EditorSnapshot,
17345        position: Point,
17346    ) -> Option<MultiBufferRow> {
17347        snapshot
17348            .buffer_snapshot()
17349            .diff_hunk_before(position)
17350            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17351    }
17352
17353    fn go_to_next_change(
17354        &mut self,
17355        _: &GoToNextChange,
17356        window: &mut Window,
17357        cx: &mut Context<Self>,
17358    ) {
17359        if let Some(selections) = self
17360            .change_list
17361            .next_change(1, Direction::Next)
17362            .map(|s| s.to_vec())
17363        {
17364            self.change_selections(Default::default(), window, cx, |s| {
17365                let map = s.display_snapshot();
17366                s.select_display_ranges(selections.iter().map(|a| {
17367                    let point = a.to_display_point(&map);
17368                    point..point
17369                }))
17370            })
17371        }
17372    }
17373
17374    fn go_to_previous_change(
17375        &mut self,
17376        _: &GoToPreviousChange,
17377        window: &mut Window,
17378        cx: &mut Context<Self>,
17379    ) {
17380        if let Some(selections) = self
17381            .change_list
17382            .next_change(1, Direction::Prev)
17383            .map(|s| s.to_vec())
17384        {
17385            self.change_selections(Default::default(), window, cx, |s| {
17386                let map = s.display_snapshot();
17387                s.select_display_ranges(selections.iter().map(|a| {
17388                    let point = a.to_display_point(&map);
17389                    point..point
17390                }))
17391            })
17392        }
17393    }
17394
17395    pub fn go_to_next_document_highlight(
17396        &mut self,
17397        _: &GoToNextDocumentHighlight,
17398        window: &mut Window,
17399        cx: &mut Context<Self>,
17400    ) {
17401        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17402    }
17403
17404    pub fn go_to_prev_document_highlight(
17405        &mut self,
17406        _: &GoToPreviousDocumentHighlight,
17407        window: &mut Window,
17408        cx: &mut Context<Self>,
17409    ) {
17410        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17411    }
17412
17413    pub fn go_to_document_highlight_before_or_after_position(
17414        &mut self,
17415        direction: Direction,
17416        window: &mut Window,
17417        cx: &mut Context<Editor>,
17418    ) {
17419        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17420        let snapshot = self.snapshot(window, cx);
17421        let buffer = &snapshot.buffer_snapshot();
17422        let position = self
17423            .selections
17424            .newest::<Point>(&snapshot.display_snapshot)
17425            .head();
17426        let anchor_position = buffer.anchor_after(position);
17427
17428        // Get all document highlights (both read and write)
17429        let mut all_highlights = Vec::new();
17430
17431        if let Some((_, read_highlights)) = self
17432            .background_highlights
17433            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
17434        {
17435            all_highlights.extend(read_highlights.iter());
17436        }
17437
17438        if let Some((_, write_highlights)) = self
17439            .background_highlights
17440            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17441        {
17442            all_highlights.extend(write_highlights.iter());
17443        }
17444
17445        if all_highlights.is_empty() {
17446            return;
17447        }
17448
17449        // Sort highlights by position
17450        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17451
17452        let target_highlight = match direction {
17453            Direction::Next => {
17454                // Find the first highlight after the current position
17455                all_highlights
17456                    .iter()
17457                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17458            }
17459            Direction::Prev => {
17460                // Find the last highlight before the current position
17461                all_highlights
17462                    .iter()
17463                    .rev()
17464                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17465            }
17466        };
17467
17468        if let Some(highlight) = target_highlight {
17469            let destination = highlight.start.to_point(buffer);
17470            let autoscroll = Autoscroll::center();
17471
17472            self.unfold_ranges(&[destination..destination], false, false, cx);
17473            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17474                s.select_ranges([destination..destination]);
17475            });
17476        }
17477    }
17478
17479    fn go_to_line<T: 'static>(
17480        &mut self,
17481        position: Anchor,
17482        highlight_color: Option<Hsla>,
17483        window: &mut Window,
17484        cx: &mut Context<Self>,
17485    ) {
17486        let snapshot = self.snapshot(window, cx).display_snapshot;
17487        let position = position.to_point(&snapshot.buffer_snapshot());
17488        let start = snapshot
17489            .buffer_snapshot()
17490            .clip_point(Point::new(position.row, 0), Bias::Left);
17491        let end = start + Point::new(1, 0);
17492        let start = snapshot.buffer_snapshot().anchor_before(start);
17493        let end = snapshot.buffer_snapshot().anchor_before(end);
17494
17495        self.highlight_rows::<T>(
17496            start..end,
17497            highlight_color
17498                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17499            Default::default(),
17500            cx,
17501        );
17502
17503        if self.buffer.read(cx).is_singleton() {
17504            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17505        }
17506    }
17507
17508    pub fn go_to_definition(
17509        &mut self,
17510        _: &GoToDefinition,
17511        window: &mut Window,
17512        cx: &mut Context<Self>,
17513    ) -> Task<Result<Navigated>> {
17514        let definition =
17515            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17516        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17517        cx.spawn_in(window, async move |editor, cx| {
17518            if definition.await? == Navigated::Yes {
17519                return Ok(Navigated::Yes);
17520            }
17521            match fallback_strategy {
17522                GoToDefinitionFallback::None => Ok(Navigated::No),
17523                GoToDefinitionFallback::FindAllReferences => {
17524                    match editor.update_in(cx, |editor, window, cx| {
17525                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17526                    })? {
17527                        Some(references) => references.await,
17528                        None => Ok(Navigated::No),
17529                    }
17530                }
17531            }
17532        })
17533    }
17534
17535    pub fn go_to_declaration(
17536        &mut self,
17537        _: &GoToDeclaration,
17538        window: &mut Window,
17539        cx: &mut Context<Self>,
17540    ) -> Task<Result<Navigated>> {
17541        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17542    }
17543
17544    pub fn go_to_declaration_split(
17545        &mut self,
17546        _: &GoToDeclaration,
17547        window: &mut Window,
17548        cx: &mut Context<Self>,
17549    ) -> Task<Result<Navigated>> {
17550        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17551    }
17552
17553    pub fn go_to_implementation(
17554        &mut self,
17555        _: &GoToImplementation,
17556        window: &mut Window,
17557        cx: &mut Context<Self>,
17558    ) -> Task<Result<Navigated>> {
17559        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17560    }
17561
17562    pub fn go_to_implementation_split(
17563        &mut self,
17564        _: &GoToImplementationSplit,
17565        window: &mut Window,
17566        cx: &mut Context<Self>,
17567    ) -> Task<Result<Navigated>> {
17568        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17569    }
17570
17571    pub fn go_to_type_definition(
17572        &mut self,
17573        _: &GoToTypeDefinition,
17574        window: &mut Window,
17575        cx: &mut Context<Self>,
17576    ) -> Task<Result<Navigated>> {
17577        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17578    }
17579
17580    pub fn go_to_definition_split(
17581        &mut self,
17582        _: &GoToDefinitionSplit,
17583        window: &mut Window,
17584        cx: &mut Context<Self>,
17585    ) -> Task<Result<Navigated>> {
17586        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17587    }
17588
17589    pub fn go_to_type_definition_split(
17590        &mut self,
17591        _: &GoToTypeDefinitionSplit,
17592        window: &mut Window,
17593        cx: &mut Context<Self>,
17594    ) -> Task<Result<Navigated>> {
17595        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17596    }
17597
17598    fn go_to_definition_of_kind(
17599        &mut self,
17600        kind: GotoDefinitionKind,
17601        split: bool,
17602        window: &mut Window,
17603        cx: &mut Context<Self>,
17604    ) -> Task<Result<Navigated>> {
17605        let Some(provider) = self.semantics_provider.clone() else {
17606            return Task::ready(Ok(Navigated::No));
17607        };
17608        let head = self
17609            .selections
17610            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17611            .head();
17612        let buffer = self.buffer.read(cx);
17613        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17614            return Task::ready(Ok(Navigated::No));
17615        };
17616        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17617            return Task::ready(Ok(Navigated::No));
17618        };
17619
17620        let nav_entry = self.navigation_entry(self.selections.newest_anchor().head(), cx);
17621
17622        cx.spawn_in(window, async move |editor, cx| {
17623            let Some(definitions) = definitions.await? else {
17624                return Ok(Navigated::No);
17625            };
17626            let navigated = editor
17627                .update_in(cx, |editor, window, cx| {
17628                    editor.navigate_to_hover_links(
17629                        Some(kind),
17630                        definitions
17631                            .into_iter()
17632                            .filter(|location| {
17633                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17634                            })
17635                            .map(HoverLink::Text)
17636                            .collect::<Vec<_>>(),
17637                        nav_entry,
17638                        split,
17639                        window,
17640                        cx,
17641                    )
17642                })?
17643                .await?;
17644            anyhow::Ok(navigated)
17645        })
17646    }
17647
17648    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17649        let selection = self.selections.newest_anchor();
17650        let head = selection.head();
17651        let tail = selection.tail();
17652
17653        let Some((buffer, start_position)) =
17654            self.buffer.read(cx).text_anchor_for_position(head, cx)
17655        else {
17656            return;
17657        };
17658
17659        let end_position = if head != tail {
17660            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17661                return;
17662            };
17663            Some(pos)
17664        } else {
17665            None
17666        };
17667
17668        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17669            let url = if let Some(end_pos) = end_position {
17670                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17671            } else {
17672                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17673            };
17674
17675            if let Some(url) = url {
17676                cx.update(|window, cx| {
17677                    if parse_zed_link(&url, cx).is_some() {
17678                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17679                    } else {
17680                        cx.open_url(&url);
17681                    }
17682                })?;
17683            }
17684
17685            anyhow::Ok(())
17686        });
17687
17688        url_finder.detach();
17689    }
17690
17691    pub fn open_selected_filename(
17692        &mut self,
17693        _: &OpenSelectedFilename,
17694        window: &mut Window,
17695        cx: &mut Context<Self>,
17696    ) {
17697        let Some(workspace) = self.workspace() else {
17698            return;
17699        };
17700
17701        let position = self.selections.newest_anchor().head();
17702
17703        let Some((buffer, buffer_position)) =
17704            self.buffer.read(cx).text_anchor_for_position(position, cx)
17705        else {
17706            return;
17707        };
17708
17709        let project = self.project.clone();
17710
17711        cx.spawn_in(window, async move |_, cx| {
17712            let result = find_file(&buffer, project, buffer_position, cx).await;
17713
17714            if let Some((_, path)) = result {
17715                workspace
17716                    .update_in(cx, |workspace, window, cx| {
17717                        workspace.open_resolved_path(path, window, cx)
17718                    })?
17719                    .await?;
17720            }
17721            anyhow::Ok(())
17722        })
17723        .detach();
17724    }
17725
17726    pub(crate) fn navigate_to_hover_links(
17727        &mut self,
17728        kind: Option<GotoDefinitionKind>,
17729        definitions: Vec<HoverLink>,
17730        origin: Option<NavigationEntry>,
17731        split: bool,
17732        window: &mut Window,
17733        cx: &mut Context<Editor>,
17734    ) -> Task<Result<Navigated>> {
17735        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17736        let mut first_url_or_file = None;
17737        let definitions: Vec<_> = definitions
17738            .into_iter()
17739            .filter_map(|def| match def {
17740                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17741                HoverLink::InlayHint(lsp_location, server_id) => {
17742                    let computation =
17743                        self.compute_target_location(lsp_location, server_id, window, cx);
17744                    Some(cx.background_spawn(computation))
17745                }
17746                HoverLink::Url(url) => {
17747                    first_url_or_file = Some(Either::Left(url));
17748                    None
17749                }
17750                HoverLink::File(path) => {
17751                    first_url_or_file = Some(Either::Right(path));
17752                    None
17753                }
17754            })
17755            .collect();
17756
17757        let workspace = self.workspace();
17758
17759        cx.spawn_in(window, async move |editor, cx| {
17760            let locations: Vec<Location> = future::join_all(definitions)
17761                .await
17762                .into_iter()
17763                .filter_map(|location| location.transpose())
17764                .collect::<Result<_>>()
17765                .context("location tasks")?;
17766            let mut locations = cx.update(|_, cx| {
17767                locations
17768                    .into_iter()
17769                    .map(|location| {
17770                        let buffer = location.buffer.read(cx);
17771                        (location.buffer, location.range.to_point(buffer))
17772                    })
17773                    .into_group_map()
17774            })?;
17775            let mut num_locations = 0;
17776            for ranges in locations.values_mut() {
17777                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17778                ranges.dedup();
17779                num_locations += ranges.len();
17780            }
17781
17782            if num_locations > 1 {
17783                let tab_kind = match kind {
17784                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17785                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17786                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17787                    Some(GotoDefinitionKind::Type) => "Types",
17788                };
17789                let title = editor
17790                    .update_in(cx, |_, _, cx| {
17791                        let target = locations
17792                            .iter()
17793                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17794                            .map(|(buffer, location)| {
17795                                buffer
17796                                    .read(cx)
17797                                    .text_for_range(location.clone())
17798                                    .collect::<String>()
17799                            })
17800                            .filter(|text| !text.contains('\n'))
17801                            .unique()
17802                            .take(3)
17803                            .join(", ");
17804                        if target.is_empty() {
17805                            tab_kind.to_owned()
17806                        } else {
17807                            format!("{tab_kind} for {target}")
17808                        }
17809                    })
17810                    .context("buffer title")?;
17811
17812                let Some(workspace) = workspace else {
17813                    return Ok(Navigated::No);
17814                };
17815
17816                let opened = workspace
17817                    .update_in(cx, |workspace, window, cx| {
17818                        let allow_preview = PreviewTabsSettings::get_global(cx)
17819                            .enable_preview_multibuffer_from_code_navigation;
17820                        if let Some((target_editor, target_pane)) =
17821                            Self::open_locations_in_multibuffer(
17822                                workspace,
17823                                locations,
17824                                title,
17825                                split,
17826                                allow_preview,
17827                                MultibufferSelectionMode::First,
17828                                window,
17829                                cx,
17830                            )
17831                        {
17832                            // We create our own nav history instead of using
17833                            // `target_editor.nav_history` because `nav_history`
17834                            // seems to be populated asynchronously when an item
17835                            // is added to a pane
17836                            let mut nav_history = target_pane
17837                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
17838                            target_editor.update(cx, |editor, cx| {
17839                                let nav_data = editor
17840                                    .navigation_data(editor.selections.newest_anchor().head(), cx);
17841                                let target =
17842                                    Some(nav_history.navigation_entry(Some(
17843                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
17844                                    )));
17845                                nav_history.push_tag(origin, target);
17846                            })
17847                        }
17848                    })
17849                    .is_ok();
17850
17851                anyhow::Ok(Navigated::from_bool(opened))
17852            } else if num_locations == 0 {
17853                // If there is one url or file, open it directly
17854                match first_url_or_file {
17855                    Some(Either::Left(url)) => {
17856                        cx.update(|window, cx| {
17857                            if parse_zed_link(&url, cx).is_some() {
17858                                window
17859                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17860                            } else {
17861                                cx.open_url(&url);
17862                            }
17863                        })?;
17864                        Ok(Navigated::Yes)
17865                    }
17866                    Some(Either::Right(path)) => {
17867                        // TODO(andrew): respect preview tab settings
17868                        //               `enable_keep_preview_on_code_navigation` and
17869                        //               `enable_preview_file_from_code_navigation`
17870                        let Some(workspace) = workspace else {
17871                            return Ok(Navigated::No);
17872                        };
17873                        workspace
17874                            .update_in(cx, |workspace, window, cx| {
17875                                workspace.open_resolved_path(path, window, cx)
17876                            })?
17877                            .await?;
17878                        Ok(Navigated::Yes)
17879                    }
17880                    None => Ok(Navigated::No),
17881                }
17882            } else {
17883                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17884                let target_range = target_ranges.first().unwrap().clone();
17885
17886                editor.update_in(cx, |editor, window, cx| {
17887                    let range = editor.range_for_match(&target_range);
17888                    let range = collapse_multiline_range(range);
17889
17890                    if !split
17891                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17892                    {
17893                        editor.go_to_singleton_buffer_range(range, window, cx);
17894
17895                        let target =
17896                            editor.navigation_entry(editor.selections.newest_anchor().head(), cx);
17897                        if let Some(mut nav_history) = editor.nav_history.clone() {
17898                            nav_history.push_tag(origin, target);
17899                        }
17900                    } else {
17901                        let Some(workspace) = workspace else {
17902                            return Navigated::No;
17903                        };
17904                        let pane = workspace.read(cx).active_pane().clone();
17905                        window.defer(cx, move |window, cx| {
17906                            let (target_editor, target_pane): (Entity<Self>, Entity<Pane>) =
17907                                workspace.update(cx, |workspace, cx| {
17908                                    let pane = if split {
17909                                        workspace.adjacent_pane(window, cx)
17910                                    } else {
17911                                        workspace.active_pane().clone()
17912                                    };
17913
17914                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17915                                    let keep_old_preview = preview_tabs_settings
17916                                        .enable_keep_preview_on_code_navigation;
17917                                    let allow_new_preview = preview_tabs_settings
17918                                        .enable_preview_file_from_code_navigation;
17919
17920                                    let editor = workspace.open_project_item(
17921                                        pane.clone(),
17922                                        target_buffer.clone(),
17923                                        true,
17924                                        true,
17925                                        keep_old_preview,
17926                                        allow_new_preview,
17927                                        window,
17928                                        cx,
17929                                    );
17930                                    (editor, pane)
17931                                });
17932                            // We create our own nav history instead of using
17933                            // `target_editor.nav_history` because `nav_history`
17934                            // seems to be populated asynchronously when an item
17935                            // is added to a pane
17936                            let mut nav_history = target_pane
17937                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
17938                            target_editor.update(cx, |target_editor, cx| {
17939                                // When selecting a definition in a different buffer, disable the nav history
17940                                // to avoid creating a history entry at the previous cursor location.
17941                                pane.update(cx, |pane, _| pane.disable_history());
17942                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17943
17944                                let nav_data = target_editor.navigation_data(
17945                                    target_editor.selections.newest_anchor().head(),
17946                                    cx,
17947                                );
17948                                let target =
17949                                    Some(nav_history.navigation_entry(Some(
17950                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
17951                                    )));
17952                                nav_history.push_tag(origin, target);
17953                                pane.update(cx, |pane, _| pane.enable_history());
17954                            });
17955                        });
17956                    }
17957                    Navigated::Yes
17958                })
17959            }
17960        })
17961    }
17962
17963    fn compute_target_location(
17964        &self,
17965        lsp_location: lsp::Location,
17966        server_id: LanguageServerId,
17967        window: &mut Window,
17968        cx: &mut Context<Self>,
17969    ) -> Task<anyhow::Result<Option<Location>>> {
17970        let Some(project) = self.project.clone() else {
17971            return Task::ready(Ok(None));
17972        };
17973
17974        cx.spawn_in(window, async move |editor, cx| {
17975            let location_task = editor.update(cx, |_, cx| {
17976                project.update(cx, |project, cx| {
17977                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17978                })
17979            })?;
17980            let location = Some({
17981                let target_buffer_handle = location_task.await.context("open local buffer")?;
17982                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17983                    let target_start = target_buffer
17984                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17985                    let target_end = target_buffer
17986                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17987                    target_buffer.anchor_after(target_start)
17988                        ..target_buffer.anchor_before(target_end)
17989                });
17990                Location {
17991                    buffer: target_buffer_handle,
17992                    range,
17993                }
17994            });
17995            Ok(location)
17996        })
17997    }
17998
17999    fn go_to_next_reference(
18000        &mut self,
18001        _: &GoToNextReference,
18002        window: &mut Window,
18003        cx: &mut Context<Self>,
18004    ) {
18005        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
18006        if let Some(task) = task {
18007            task.detach();
18008        };
18009    }
18010
18011    fn go_to_prev_reference(
18012        &mut self,
18013        _: &GoToPreviousReference,
18014        window: &mut Window,
18015        cx: &mut Context<Self>,
18016    ) {
18017        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
18018        if let Some(task) = task {
18019            task.detach();
18020        };
18021    }
18022
18023    pub fn go_to_reference_before_or_after_position(
18024        &mut self,
18025        direction: Direction,
18026        count: usize,
18027        window: &mut Window,
18028        cx: &mut Context<Self>,
18029    ) -> Option<Task<Result<()>>> {
18030        let selection = self.selections.newest_anchor();
18031        let head = selection.head();
18032
18033        let multi_buffer = self.buffer.read(cx);
18034
18035        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
18036        let workspace = self.workspace()?;
18037        let project = workspace.read(cx).project().clone();
18038        let references =
18039            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
18040        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
18041            let Some(locations) = references.await? else {
18042                return Ok(());
18043            };
18044
18045            if locations.is_empty() {
18046                // totally normal - the cursor may be on something which is not
18047                // a symbol (e.g. a keyword)
18048                log::info!("no references found under cursor");
18049                return Ok(());
18050            }
18051
18052            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
18053
18054            let (locations, current_location_index) =
18055                multi_buffer.update(cx, |multi_buffer, cx| {
18056                    let mut locations = locations
18057                        .into_iter()
18058                        .filter_map(|loc| {
18059                            let start = multi_buffer.buffer_anchor_to_anchor(
18060                                &loc.buffer,
18061                                loc.range.start,
18062                                cx,
18063                            )?;
18064                            let end = multi_buffer.buffer_anchor_to_anchor(
18065                                &loc.buffer,
18066                                loc.range.end,
18067                                cx,
18068                            )?;
18069                            Some(start..end)
18070                        })
18071                        .collect::<Vec<_>>();
18072
18073                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18074                    // There is an O(n) implementation, but given this list will be
18075                    // small (usually <100 items), the extra O(log(n)) factor isn't
18076                    // worth the (surprisingly large amount of) extra complexity.
18077                    locations
18078                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
18079
18080                    let head_offset = head.to_offset(&multi_buffer_snapshot);
18081
18082                    let current_location_index = locations.iter().position(|loc| {
18083                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
18084                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
18085                    });
18086
18087                    (locations, current_location_index)
18088                });
18089
18090            let Some(current_location_index) = current_location_index else {
18091                // This indicates something has gone wrong, because we already
18092                // handle the "no references" case above
18093                log::error!(
18094                    "failed to find current reference under cursor. Total references: {}",
18095                    locations.len()
18096                );
18097                return Ok(());
18098            };
18099
18100            let destination_location_index = match direction {
18101                Direction::Next => (current_location_index + count) % locations.len(),
18102                Direction::Prev => {
18103                    (current_location_index + locations.len() - count % locations.len())
18104                        % locations.len()
18105                }
18106            };
18107
18108            // TODO(cameron): is this needed?
18109            // the thinking is to avoid "jumping to the current location" (avoid
18110            // polluting "jumplist" in vim terms)
18111            if current_location_index == destination_location_index {
18112                return Ok(());
18113            }
18114
18115            let Range { start, end } = locations[destination_location_index];
18116
18117            editor.update_in(cx, |editor, window, cx| {
18118                let effects = SelectionEffects::default();
18119
18120                editor.unfold_ranges(&[start..end], false, false, cx);
18121                editor.change_selections(effects, window, cx, |s| {
18122                    s.select_ranges([start..start]);
18123                });
18124            })?;
18125
18126            Ok(())
18127        }))
18128    }
18129
18130    pub fn find_all_references(
18131        &mut self,
18132        action: &FindAllReferences,
18133        window: &mut Window,
18134        cx: &mut Context<Self>,
18135    ) -> Option<Task<Result<Navigated>>> {
18136        let always_open_multibuffer = action.always_open_multibuffer;
18137        let selection = self.selections.newest_anchor();
18138        let multi_buffer = self.buffer.read(cx);
18139        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18140        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
18141        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
18142        let head = selection_offset.head();
18143
18144        let head_anchor = multi_buffer_snapshot.anchor_at(
18145            head,
18146            if head < selection_offset.tail() {
18147                Bias::Right
18148            } else {
18149                Bias::Left
18150            },
18151        );
18152
18153        match self
18154            .find_all_references_task_sources
18155            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18156        {
18157            Ok(_) => {
18158                log::info!(
18159                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
18160                );
18161                return None;
18162            }
18163            Err(i) => {
18164                self.find_all_references_task_sources.insert(i, head_anchor);
18165            }
18166        }
18167
18168        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
18169        let workspace = self.workspace()?;
18170        let project = workspace.read(cx).project().clone();
18171        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
18172        Some(cx.spawn_in(window, async move |editor, cx| {
18173            let _cleanup = cx.on_drop(&editor, move |editor, _| {
18174                if let Ok(i) = editor
18175                    .find_all_references_task_sources
18176                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18177                {
18178                    editor.find_all_references_task_sources.remove(i);
18179                }
18180            });
18181
18182            let Some(locations) = references.await? else {
18183                return anyhow::Ok(Navigated::No);
18184            };
18185            let mut locations = cx.update(|_, cx| {
18186                locations
18187                    .into_iter()
18188                    .map(|location| {
18189                        let buffer = location.buffer.read(cx);
18190                        (location.buffer, location.range.to_point(buffer))
18191                    })
18192                    // if special-casing the single-match case, remove ranges
18193                    // that intersect current selection
18194                    .filter(|(location_buffer, location)| {
18195                        if always_open_multibuffer || &buffer != location_buffer {
18196                            return true;
18197                        }
18198
18199                        !location.contains_inclusive(&selection_point.range())
18200                    })
18201                    .into_group_map()
18202            })?;
18203            if locations.is_empty() {
18204                return anyhow::Ok(Navigated::No);
18205            }
18206            for ranges in locations.values_mut() {
18207                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18208                ranges.dedup();
18209            }
18210            let mut num_locations = 0;
18211            for ranges in locations.values_mut() {
18212                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18213                ranges.dedup();
18214                num_locations += ranges.len();
18215            }
18216
18217            if num_locations == 1 && !always_open_multibuffer {
18218                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18219                let target_range = target_ranges.first().unwrap().clone();
18220
18221                return editor.update_in(cx, |editor, window, cx| {
18222                    let range = target_range.to_point(target_buffer.read(cx));
18223                    let range = editor.range_for_match(&range);
18224                    let range = range.start..range.start;
18225
18226                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
18227                        editor.go_to_singleton_buffer_range(range, window, cx);
18228                    } else {
18229                        let pane = workspace.read(cx).active_pane().clone();
18230                        window.defer(cx, move |window, cx| {
18231                            let target_editor: Entity<Self> =
18232                                workspace.update(cx, |workspace, cx| {
18233                                    let pane = workspace.active_pane().clone();
18234
18235                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18236                                    let keep_old_preview = preview_tabs_settings
18237                                        .enable_keep_preview_on_code_navigation;
18238                                    let allow_new_preview = preview_tabs_settings
18239                                        .enable_preview_file_from_code_navigation;
18240
18241                                    workspace.open_project_item(
18242                                        pane,
18243                                        target_buffer.clone(),
18244                                        true,
18245                                        true,
18246                                        keep_old_preview,
18247                                        allow_new_preview,
18248                                        window,
18249                                        cx,
18250                                    )
18251                                });
18252                            target_editor.update(cx, |target_editor, cx| {
18253                                // When selecting a definition in a different buffer, disable the nav history
18254                                // to avoid creating a history entry at the previous cursor location.
18255                                pane.update(cx, |pane, _| pane.disable_history());
18256                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18257                                pane.update(cx, |pane, _| pane.enable_history());
18258                            });
18259                        });
18260                    }
18261                    Navigated::No
18262                });
18263            }
18264
18265            workspace.update_in(cx, |workspace, window, cx| {
18266                let target = locations
18267                    .iter()
18268                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18269                    .map(|(buffer, location)| {
18270                        buffer
18271                            .read(cx)
18272                            .text_for_range(location.clone())
18273                            .collect::<String>()
18274                    })
18275                    .filter(|text| !text.contains('\n'))
18276                    .unique()
18277                    .take(3)
18278                    .join(", ");
18279                let title = if target.is_empty() {
18280                    "References".to_owned()
18281                } else {
18282                    format!("References to {target}")
18283                };
18284                let allow_preview = PreviewTabsSettings::get_global(cx)
18285                    .enable_preview_multibuffer_from_code_navigation;
18286                Self::open_locations_in_multibuffer(
18287                    workspace,
18288                    locations,
18289                    title,
18290                    false,
18291                    allow_preview,
18292                    MultibufferSelectionMode::First,
18293                    window,
18294                    cx,
18295                );
18296                Navigated::Yes
18297            })
18298        }))
18299    }
18300
18301    /// Opens a multibuffer with the given project locations in it.
18302    pub fn open_locations_in_multibuffer(
18303        workspace: &mut Workspace,
18304        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
18305        title: String,
18306        split: bool,
18307        allow_preview: bool,
18308        multibuffer_selection_mode: MultibufferSelectionMode,
18309        window: &mut Window,
18310        cx: &mut Context<Workspace>,
18311    ) -> Option<(Entity<Editor>, Entity<Pane>)> {
18312        if locations.is_empty() {
18313            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
18314            return None;
18315        }
18316
18317        let capability = workspace.project().read(cx).capability();
18318        let mut ranges = <Vec<Range<Anchor>>>::new();
18319
18320        // a key to find existing multibuffer editors with the same set of locations
18321        // to prevent us from opening more and more multibuffer tabs for searches and the like
18322        let mut key = (title.clone(), vec![]);
18323        let excerpt_buffer = cx.new(|cx| {
18324            let key = &mut key.1;
18325            let mut multibuffer = MultiBuffer::new(capability);
18326            for (buffer, mut ranges_for_buffer) in locations {
18327                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
18328                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
18329                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
18330                    PathKey::for_buffer(&buffer, cx),
18331                    buffer.clone(),
18332                    ranges_for_buffer,
18333                    multibuffer_context_lines(cx),
18334                    cx,
18335                );
18336                ranges.extend(new_ranges)
18337            }
18338
18339            multibuffer.with_title(title)
18340        });
18341        let existing = workspace.active_pane().update(cx, |pane, cx| {
18342            pane.items()
18343                .filter_map(|item| item.downcast::<Editor>())
18344                .find(|editor| {
18345                    editor
18346                        .read(cx)
18347                        .lookup_key
18348                        .as_ref()
18349                        .and_then(|it| {
18350                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
18351                        })
18352                        .is_some_and(|it| *it == key)
18353                })
18354        });
18355        let was_existing = existing.is_some();
18356        let editor = existing.unwrap_or_else(|| {
18357            cx.new(|cx| {
18358                let mut editor = Editor::for_multibuffer(
18359                    excerpt_buffer,
18360                    Some(workspace.project().clone()),
18361                    window,
18362                    cx,
18363                );
18364                editor.lookup_key = Some(Box::new(key));
18365                editor
18366            })
18367        });
18368        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
18369            MultibufferSelectionMode::First => {
18370                if let Some(first_range) = ranges.first() {
18371                    editor.change_selections(
18372                        SelectionEffects::no_scroll(),
18373                        window,
18374                        cx,
18375                        |selections| {
18376                            selections.clear_disjoint();
18377                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
18378                        },
18379                    );
18380                }
18381                editor.highlight_background::<Self>(
18382                    &ranges,
18383                    |_, theme| theme.colors().editor_highlighted_line_background,
18384                    cx,
18385                );
18386            }
18387            MultibufferSelectionMode::All => {
18388                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
18389                    selections.clear_disjoint();
18390                    selections.select_anchor_ranges(ranges);
18391                });
18392            }
18393        });
18394
18395        let item = Box::new(editor.clone());
18396
18397        let pane = if split {
18398            workspace.adjacent_pane(window, cx)
18399        } else {
18400            workspace.active_pane().clone()
18401        };
18402        let activate_pane = split;
18403
18404        let mut destination_index = None;
18405        pane.update(cx, |pane, cx| {
18406            if allow_preview && !was_existing {
18407                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18408            }
18409            if was_existing && !allow_preview {
18410                pane.unpreview_item_if_preview(item.item_id());
18411            }
18412            pane.add_item(item, activate_pane, true, destination_index, window, cx);
18413        });
18414
18415        Some((editor, pane))
18416    }
18417
18418    pub fn rename(
18419        &mut self,
18420        _: &Rename,
18421        window: &mut Window,
18422        cx: &mut Context<Self>,
18423    ) -> Option<Task<Result<()>>> {
18424        use language::ToOffset as _;
18425
18426        let provider = self.semantics_provider.clone()?;
18427        let selection = self.selections.newest_anchor().clone();
18428        let (cursor_buffer, cursor_buffer_position) = self
18429            .buffer
18430            .read(cx)
18431            .text_anchor_for_position(selection.head(), cx)?;
18432        let (tail_buffer, cursor_buffer_position_end) = self
18433            .buffer
18434            .read(cx)
18435            .text_anchor_for_position(selection.tail(), cx)?;
18436        if tail_buffer != cursor_buffer {
18437            return None;
18438        }
18439
18440        let snapshot = cursor_buffer.read(cx).snapshot();
18441        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
18442        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
18443        let prepare_rename = provider
18444            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
18445            .unwrap_or_else(|| Task::ready(Ok(None)));
18446        drop(snapshot);
18447
18448        Some(cx.spawn_in(window, async move |this, cx| {
18449            let rename_range = if let Some(range) = prepare_rename.await? {
18450                Some(range)
18451            } else {
18452                this.update(cx, |this, cx| {
18453                    let buffer = this.buffer.read(cx).snapshot(cx);
18454                    let mut buffer_highlights = this
18455                        .document_highlights_for_position(selection.head(), &buffer)
18456                        .filter(|highlight| {
18457                            highlight.start.excerpt_id == selection.head().excerpt_id
18458                                && highlight.end.excerpt_id == selection.head().excerpt_id
18459                        });
18460                    buffer_highlights
18461                        .next()
18462                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18463                })?
18464            };
18465            if let Some(rename_range) = rename_range {
18466                this.update_in(cx, |this, window, cx| {
18467                    let snapshot = cursor_buffer.read(cx).snapshot();
18468                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18469                    let cursor_offset_in_rename_range =
18470                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18471                    let cursor_offset_in_rename_range_end =
18472                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18473
18474                    this.take_rename(false, window, cx);
18475                    let buffer = this.buffer.read(cx).read(cx);
18476                    let cursor_offset = selection.head().to_offset(&buffer);
18477                    let rename_start =
18478                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18479                    let rename_end = rename_start + rename_buffer_range.len();
18480                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18481                    let mut old_highlight_id = None;
18482                    let old_name: Arc<str> = buffer
18483                        .chunks(rename_start..rename_end, true)
18484                        .map(|chunk| {
18485                            if old_highlight_id.is_none() {
18486                                old_highlight_id = chunk.syntax_highlight_id;
18487                            }
18488                            chunk.text
18489                        })
18490                        .collect::<String>()
18491                        .into();
18492
18493                    drop(buffer);
18494
18495                    // Position the selection in the rename editor so that it matches the current selection.
18496                    this.show_local_selections = false;
18497                    let rename_editor = cx.new(|cx| {
18498                        let mut editor = Editor::single_line(window, cx);
18499                        editor.buffer.update(cx, |buffer, cx| {
18500                            buffer.edit(
18501                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18502                                None,
18503                                cx,
18504                            )
18505                        });
18506                        let cursor_offset_in_rename_range =
18507                            MultiBufferOffset(cursor_offset_in_rename_range);
18508                        let cursor_offset_in_rename_range_end =
18509                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18510                        let rename_selection_range = match cursor_offset_in_rename_range
18511                            .cmp(&cursor_offset_in_rename_range_end)
18512                        {
18513                            Ordering::Equal => {
18514                                editor.select_all(&SelectAll, window, cx);
18515                                return editor;
18516                            }
18517                            Ordering::Less => {
18518                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18519                            }
18520                            Ordering::Greater => {
18521                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18522                            }
18523                        };
18524                        if rename_selection_range.end.0 > old_name.len() {
18525                            editor.select_all(&SelectAll, window, cx);
18526                        } else {
18527                            editor.change_selections(Default::default(), window, cx, |s| {
18528                                s.select_ranges([rename_selection_range]);
18529                            });
18530                        }
18531                        editor
18532                    });
18533                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18534                        if e == &EditorEvent::Focused {
18535                            cx.emit(EditorEvent::FocusedIn)
18536                        }
18537                    })
18538                    .detach();
18539
18540                    let write_highlights =
18541                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18542                    let read_highlights =
18543                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18544                    let ranges = write_highlights
18545                        .iter()
18546                        .flat_map(|(_, ranges)| ranges.iter())
18547                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18548                        .cloned()
18549                        .collect();
18550
18551                    this.highlight_text::<Rename>(
18552                        ranges,
18553                        HighlightStyle {
18554                            fade_out: Some(0.6),
18555                            ..Default::default()
18556                        },
18557                        cx,
18558                    );
18559                    let rename_focus_handle = rename_editor.focus_handle(cx);
18560                    window.focus(&rename_focus_handle, cx);
18561                    let block_id = this.insert_blocks(
18562                        [BlockProperties {
18563                            style: BlockStyle::Flex,
18564                            placement: BlockPlacement::Below(range.start),
18565                            height: Some(1),
18566                            render: Arc::new({
18567                                let rename_editor = rename_editor.clone();
18568                                move |cx: &mut BlockContext| {
18569                                    let mut text_style = cx.editor_style.text.clone();
18570                                    if let Some(highlight_style) = old_highlight_id
18571                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18572                                    {
18573                                        text_style = text_style.highlight(highlight_style);
18574                                    }
18575                                    div()
18576                                        .block_mouse_except_scroll()
18577                                        .pl(cx.anchor_x)
18578                                        .child(EditorElement::new(
18579                                            &rename_editor,
18580                                            EditorStyle {
18581                                                background: cx.theme().system().transparent,
18582                                                local_player: cx.editor_style.local_player,
18583                                                text: text_style,
18584                                                scrollbar_width: cx.editor_style.scrollbar_width,
18585                                                syntax: cx.editor_style.syntax.clone(),
18586                                                status: cx.editor_style.status.clone(),
18587                                                inlay_hints_style: HighlightStyle {
18588                                                    font_weight: Some(FontWeight::BOLD),
18589                                                    ..make_inlay_hints_style(cx.app)
18590                                                },
18591                                                edit_prediction_styles: make_suggestion_styles(
18592                                                    cx.app,
18593                                                ),
18594                                                ..EditorStyle::default()
18595                                            },
18596                                        ))
18597                                        .into_any_element()
18598                                }
18599                            }),
18600                            priority: 0,
18601                        }],
18602                        Some(Autoscroll::fit()),
18603                        cx,
18604                    )[0];
18605                    this.pending_rename = Some(RenameState {
18606                        range,
18607                        old_name,
18608                        editor: rename_editor,
18609                        block_id,
18610                    });
18611                })?;
18612            }
18613
18614            Ok(())
18615        }))
18616    }
18617
18618    pub fn confirm_rename(
18619        &mut self,
18620        _: &ConfirmRename,
18621        window: &mut Window,
18622        cx: &mut Context<Self>,
18623    ) -> Option<Task<Result<()>>> {
18624        let rename = self.take_rename(false, window, cx)?;
18625        let workspace = self.workspace()?.downgrade();
18626        let (buffer, start) = self
18627            .buffer
18628            .read(cx)
18629            .text_anchor_for_position(rename.range.start, cx)?;
18630        let (end_buffer, _) = self
18631            .buffer
18632            .read(cx)
18633            .text_anchor_for_position(rename.range.end, cx)?;
18634        if buffer != end_buffer {
18635            return None;
18636        }
18637
18638        let old_name = rename.old_name;
18639        let new_name = rename.editor.read(cx).text(cx);
18640
18641        let rename = self.semantics_provider.as_ref()?.perform_rename(
18642            &buffer,
18643            start,
18644            new_name.clone(),
18645            cx,
18646        )?;
18647
18648        Some(cx.spawn_in(window, async move |editor, cx| {
18649            let project_transaction = rename.await?;
18650            Self::open_project_transaction(
18651                &editor,
18652                workspace,
18653                project_transaction,
18654                format!("Rename: {}{}", old_name, new_name),
18655                cx,
18656            )
18657            .await?;
18658
18659            editor.update(cx, |editor, cx| {
18660                editor.refresh_document_highlights(cx);
18661            })?;
18662            Ok(())
18663        }))
18664    }
18665
18666    fn take_rename(
18667        &mut self,
18668        moving_cursor: bool,
18669        window: &mut Window,
18670        cx: &mut Context<Self>,
18671    ) -> Option<RenameState> {
18672        let rename = self.pending_rename.take()?;
18673        if rename.editor.focus_handle(cx).is_focused(window) {
18674            window.focus(&self.focus_handle, cx);
18675        }
18676
18677        self.remove_blocks(
18678            [rename.block_id].into_iter().collect(),
18679            Some(Autoscroll::fit()),
18680            cx,
18681        );
18682        self.clear_highlights::<Rename>(cx);
18683        self.show_local_selections = true;
18684
18685        if moving_cursor {
18686            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18687                editor
18688                    .selections
18689                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18690                    .head()
18691            });
18692
18693            // Update the selection to match the position of the selection inside
18694            // the rename editor.
18695            let snapshot = self.buffer.read(cx).read(cx);
18696            let rename_range = rename.range.to_offset(&snapshot);
18697            let cursor_in_editor = snapshot
18698                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18699                .min(rename_range.end);
18700            drop(snapshot);
18701
18702            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18703                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18704            });
18705        } else {
18706            self.refresh_document_highlights(cx);
18707        }
18708
18709        Some(rename)
18710    }
18711
18712    pub fn pending_rename(&self) -> Option<&RenameState> {
18713        self.pending_rename.as_ref()
18714    }
18715
18716    fn format(
18717        &mut self,
18718        _: &Format,
18719        window: &mut Window,
18720        cx: &mut Context<Self>,
18721    ) -> Option<Task<Result<()>>> {
18722        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18723
18724        let project = match &self.project {
18725            Some(project) => project.clone(),
18726            None => return None,
18727        };
18728
18729        Some(self.perform_format(
18730            project,
18731            FormatTrigger::Manual,
18732            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18733            window,
18734            cx,
18735        ))
18736    }
18737
18738    fn format_selections(
18739        &mut self,
18740        _: &FormatSelections,
18741        window: &mut Window,
18742        cx: &mut Context<Self>,
18743    ) -> Option<Task<Result<()>>> {
18744        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18745
18746        let project = match &self.project {
18747            Some(project) => project.clone(),
18748            None => return None,
18749        };
18750
18751        let ranges = self
18752            .selections
18753            .all_adjusted(&self.display_snapshot(cx))
18754            .into_iter()
18755            .map(|selection| selection.range())
18756            .collect_vec();
18757
18758        Some(self.perform_format(
18759            project,
18760            FormatTrigger::Manual,
18761            FormatTarget::Ranges(ranges),
18762            window,
18763            cx,
18764        ))
18765    }
18766
18767    fn perform_format(
18768        &mut self,
18769        project: Entity<Project>,
18770        trigger: FormatTrigger,
18771        target: FormatTarget,
18772        window: &mut Window,
18773        cx: &mut Context<Self>,
18774    ) -> Task<Result<()>> {
18775        let buffer = self.buffer.clone();
18776        let (buffers, target) = match target {
18777            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18778            FormatTarget::Ranges(selection_ranges) => {
18779                let multi_buffer = buffer.read(cx);
18780                let snapshot = multi_buffer.read(cx);
18781                let mut buffers = HashSet::default();
18782                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18783                    BTreeMap::new();
18784                for selection_range in selection_ranges {
18785                    for (buffer, buffer_range, _) in
18786                        snapshot.range_to_buffer_ranges(selection_range.start..=selection_range.end)
18787                    {
18788                        let buffer_id = buffer.remote_id();
18789                        let start = buffer.anchor_before(buffer_range.start);
18790                        let end = buffer.anchor_after(buffer_range.end);
18791                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18792                        buffer_id_to_ranges
18793                            .entry(buffer_id)
18794                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18795                            .or_insert_with(|| vec![start..end]);
18796                    }
18797                }
18798                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18799            }
18800        };
18801
18802        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18803        let selections_prev = transaction_id_prev
18804            .and_then(|transaction_id_prev| {
18805                // default to selections as they were after the last edit, if we have them,
18806                // instead of how they are now.
18807                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18808                // will take you back to where you made the last edit, instead of staying where you scrolled
18809                self.selection_history
18810                    .transaction(transaction_id_prev)
18811                    .map(|t| t.0.clone())
18812            })
18813            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18814
18815        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18816        let format = project.update(cx, |project, cx| {
18817            project.format(buffers, target, true, trigger, cx)
18818        });
18819
18820        cx.spawn_in(window, async move |editor, cx| {
18821            let transaction = futures::select_biased! {
18822                transaction = format.log_err().fuse() => transaction,
18823                () = timeout => {
18824                    log::warn!("timed out waiting for formatting");
18825                    None
18826                }
18827            };
18828
18829            buffer.update(cx, |buffer, cx| {
18830                if let Some(transaction) = transaction
18831                    && !buffer.is_singleton()
18832                {
18833                    buffer.push_transaction(&transaction.0, cx);
18834                }
18835                cx.notify();
18836            });
18837
18838            if let Some(transaction_id_now) =
18839                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
18840            {
18841                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18842                if has_new_transaction {
18843                    editor
18844                        .update(cx, |editor, _| {
18845                            editor
18846                                .selection_history
18847                                .insert_transaction(transaction_id_now, selections_prev);
18848                        })
18849                        .ok();
18850                }
18851            }
18852
18853            Ok(())
18854        })
18855    }
18856
18857    fn organize_imports(
18858        &mut self,
18859        _: &OrganizeImports,
18860        window: &mut Window,
18861        cx: &mut Context<Self>,
18862    ) -> Option<Task<Result<()>>> {
18863        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18864        let project = match &self.project {
18865            Some(project) => project.clone(),
18866            None => return None,
18867        };
18868        Some(self.perform_code_action_kind(
18869            project,
18870            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18871            window,
18872            cx,
18873        ))
18874    }
18875
18876    fn perform_code_action_kind(
18877        &mut self,
18878        project: Entity<Project>,
18879        kind: CodeActionKind,
18880        window: &mut Window,
18881        cx: &mut Context<Self>,
18882    ) -> Task<Result<()>> {
18883        let buffer = self.buffer.clone();
18884        let buffers = buffer.read(cx).all_buffers();
18885        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18886        let apply_action = project.update(cx, |project, cx| {
18887            project.apply_code_action_kind(buffers, kind, true, cx)
18888        });
18889        cx.spawn_in(window, async move |_, cx| {
18890            let transaction = futures::select_biased! {
18891                () = timeout => {
18892                    log::warn!("timed out waiting for executing code action");
18893                    None
18894                }
18895                transaction = apply_action.log_err().fuse() => transaction,
18896            };
18897            buffer.update(cx, |buffer, cx| {
18898                // check if we need this
18899                if let Some(transaction) = transaction
18900                    && !buffer.is_singleton()
18901                {
18902                    buffer.push_transaction(&transaction.0, cx);
18903                }
18904                cx.notify();
18905            });
18906            Ok(())
18907        })
18908    }
18909
18910    pub fn restart_language_server(
18911        &mut self,
18912        _: &RestartLanguageServer,
18913        _: &mut Window,
18914        cx: &mut Context<Self>,
18915    ) {
18916        if let Some(project) = self.project.clone() {
18917            self.buffer.update(cx, |multi_buffer, cx| {
18918                project.update(cx, |project, cx| {
18919                    project.restart_language_servers_for_buffers(
18920                        multi_buffer.all_buffers().into_iter().collect(),
18921                        HashSet::default(),
18922                        cx,
18923                    );
18924                });
18925            })
18926        }
18927    }
18928
18929    pub fn stop_language_server(
18930        &mut self,
18931        _: &StopLanguageServer,
18932        _: &mut Window,
18933        cx: &mut Context<Self>,
18934    ) {
18935        if let Some(project) = self.project.clone() {
18936            self.buffer.update(cx, |multi_buffer, cx| {
18937                project.update(cx, |project, cx| {
18938                    project.stop_language_servers_for_buffers(
18939                        multi_buffer.all_buffers().into_iter().collect(),
18940                        HashSet::default(),
18941                        cx,
18942                    );
18943                });
18944            });
18945            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18946        }
18947    }
18948
18949    fn cancel_language_server_work(
18950        workspace: &mut Workspace,
18951        _: &actions::CancelLanguageServerWork,
18952        _: &mut Window,
18953        cx: &mut Context<Workspace>,
18954    ) {
18955        let project = workspace.project();
18956        let buffers = workspace
18957            .active_item(cx)
18958            .and_then(|item| item.act_as::<Editor>(cx))
18959            .map_or(HashSet::default(), |editor| {
18960                editor.read(cx).buffer.read(cx).all_buffers()
18961            });
18962        project.update(cx, |project, cx| {
18963            project.cancel_language_server_work_for_buffers(buffers, cx);
18964        });
18965    }
18966
18967    fn show_character_palette(
18968        &mut self,
18969        _: &ShowCharacterPalette,
18970        window: &mut Window,
18971        _: &mut Context<Self>,
18972    ) {
18973        window.show_character_palette();
18974    }
18975
18976    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18977        if !self.diagnostics_enabled() {
18978            return;
18979        }
18980
18981        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18982            let buffer = self.buffer.read(cx).snapshot(cx);
18983            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18984            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18985            let is_valid = buffer
18986                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18987                .any(|entry| {
18988                    entry.diagnostic.is_primary
18989                        && !entry.range.is_empty()
18990                        && entry.range.start == primary_range_start
18991                        && entry.diagnostic.message == active_diagnostics.active_message
18992                });
18993
18994            if !is_valid {
18995                self.dismiss_diagnostics(cx);
18996            }
18997        }
18998    }
18999
19000    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
19001        match &self.active_diagnostics {
19002            ActiveDiagnostic::Group(group) => Some(group),
19003            _ => None,
19004        }
19005    }
19006
19007    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
19008        if !self.diagnostics_enabled() {
19009            return;
19010        }
19011        self.dismiss_diagnostics(cx);
19012        self.active_diagnostics = ActiveDiagnostic::All;
19013    }
19014
19015    fn activate_diagnostics(
19016        &mut self,
19017        buffer_id: BufferId,
19018        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
19019        window: &mut Window,
19020        cx: &mut Context<Self>,
19021    ) {
19022        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19023            return;
19024        }
19025        self.dismiss_diagnostics(cx);
19026        let snapshot = self.snapshot(window, cx);
19027        let buffer = self.buffer.read(cx).snapshot(cx);
19028        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
19029            return;
19030        };
19031
19032        let diagnostic_group = buffer
19033            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
19034            .collect::<Vec<_>>();
19035
19036        let language_registry = self
19037            .project()
19038            .map(|project| project.read(cx).languages().clone());
19039
19040        let blocks = renderer.render_group(
19041            diagnostic_group,
19042            buffer_id,
19043            snapshot,
19044            cx.weak_entity(),
19045            language_registry,
19046            cx,
19047        );
19048
19049        let blocks = self.display_map.update(cx, |display_map, cx| {
19050            display_map.insert_blocks(blocks, cx).into_iter().collect()
19051        });
19052        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
19053            active_range: buffer.anchor_before(diagnostic.range.start)
19054                ..buffer.anchor_after(diagnostic.range.end),
19055            active_message: diagnostic.diagnostic.message.clone(),
19056            group_id: diagnostic.diagnostic.group_id,
19057            blocks,
19058        });
19059        cx.notify();
19060    }
19061
19062    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
19063        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19064            return;
19065        };
19066
19067        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
19068        if let ActiveDiagnostic::Group(group) = prev {
19069            self.display_map.update(cx, |display_map, cx| {
19070                display_map.remove_blocks(group.blocks, cx);
19071            });
19072            cx.notify();
19073        }
19074    }
19075
19076    /// Disable inline diagnostics rendering for this editor.
19077    pub fn disable_inline_diagnostics(&mut self) {
19078        self.inline_diagnostics_enabled = false;
19079        self.inline_diagnostics_update = Task::ready(());
19080        self.inline_diagnostics.clear();
19081    }
19082
19083    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
19084        self.diagnostics_enabled = false;
19085        self.dismiss_diagnostics(cx);
19086        self.inline_diagnostics_update = Task::ready(());
19087        self.inline_diagnostics.clear();
19088    }
19089
19090    pub fn disable_word_completions(&mut self) {
19091        self.word_completions_enabled = false;
19092    }
19093
19094    pub fn diagnostics_enabled(&self) -> bool {
19095        self.diagnostics_enabled && self.mode.is_full()
19096    }
19097
19098    pub fn inline_diagnostics_enabled(&self) -> bool {
19099        self.inline_diagnostics_enabled && self.diagnostics_enabled()
19100    }
19101
19102    pub fn show_inline_diagnostics(&self) -> bool {
19103        self.show_inline_diagnostics
19104    }
19105
19106    pub fn toggle_inline_diagnostics(
19107        &mut self,
19108        _: &ToggleInlineDiagnostics,
19109        window: &mut Window,
19110        cx: &mut Context<Editor>,
19111    ) {
19112        self.show_inline_diagnostics = !self.show_inline_diagnostics;
19113        self.refresh_inline_diagnostics(false, window, cx);
19114    }
19115
19116    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
19117        self.diagnostics_max_severity = severity;
19118        self.display_map.update(cx, |display_map, _| {
19119            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
19120        });
19121    }
19122
19123    pub fn toggle_diagnostics(
19124        &mut self,
19125        _: &ToggleDiagnostics,
19126        window: &mut Window,
19127        cx: &mut Context<Editor>,
19128    ) {
19129        if !self.diagnostics_enabled() {
19130            return;
19131        }
19132
19133        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19134            EditorSettings::get_global(cx)
19135                .diagnostics_max_severity
19136                .filter(|severity| severity != &DiagnosticSeverity::Off)
19137                .unwrap_or(DiagnosticSeverity::Hint)
19138        } else {
19139            DiagnosticSeverity::Off
19140        };
19141        self.set_max_diagnostics_severity(new_severity, cx);
19142        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19143            self.active_diagnostics = ActiveDiagnostic::None;
19144            self.inline_diagnostics_update = Task::ready(());
19145            self.inline_diagnostics.clear();
19146        } else {
19147            self.refresh_inline_diagnostics(false, window, cx);
19148        }
19149
19150        cx.notify();
19151    }
19152
19153    pub fn toggle_minimap(
19154        &mut self,
19155        _: &ToggleMinimap,
19156        window: &mut Window,
19157        cx: &mut Context<Editor>,
19158    ) {
19159        if self.supports_minimap(cx) {
19160            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
19161        }
19162    }
19163
19164    fn refresh_inline_diagnostics(
19165        &mut self,
19166        debounce: bool,
19167        window: &mut Window,
19168        cx: &mut Context<Self>,
19169    ) {
19170        let max_severity = ProjectSettings::get_global(cx)
19171            .diagnostics
19172            .inline
19173            .max_severity
19174            .unwrap_or(self.diagnostics_max_severity);
19175
19176        if !self.inline_diagnostics_enabled()
19177            || !self.diagnostics_enabled()
19178            || !self.show_inline_diagnostics
19179            || max_severity == DiagnosticSeverity::Off
19180        {
19181            self.inline_diagnostics_update = Task::ready(());
19182            self.inline_diagnostics.clear();
19183            return;
19184        }
19185
19186        let debounce_ms = ProjectSettings::get_global(cx)
19187            .diagnostics
19188            .inline
19189            .update_debounce_ms;
19190        let debounce = if debounce && debounce_ms > 0 {
19191            Some(Duration::from_millis(debounce_ms))
19192        } else {
19193            None
19194        };
19195        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
19196            if let Some(debounce) = debounce {
19197                cx.background_executor().timer(debounce).await;
19198            }
19199            let Some(snapshot) = editor.upgrade().map(|editor| {
19200                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
19201            }) else {
19202                return;
19203            };
19204
19205            let new_inline_diagnostics = cx
19206                .background_spawn(async move {
19207                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
19208                    for diagnostic_entry in
19209                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
19210                    {
19211                        let message = diagnostic_entry
19212                            .diagnostic
19213                            .message
19214                            .split_once('\n')
19215                            .map(|(line, _)| line)
19216                            .map(SharedString::new)
19217                            .unwrap_or_else(|| {
19218                                SharedString::new(&*diagnostic_entry.diagnostic.message)
19219                            });
19220                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
19221                        let (Ok(i) | Err(i)) = inline_diagnostics
19222                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
19223                        inline_diagnostics.insert(
19224                            i,
19225                            (
19226                                start_anchor,
19227                                InlineDiagnostic {
19228                                    message,
19229                                    group_id: diagnostic_entry.diagnostic.group_id,
19230                                    start: diagnostic_entry.range.start.to_point(&snapshot),
19231                                    is_primary: diagnostic_entry.diagnostic.is_primary,
19232                                    severity: diagnostic_entry.diagnostic.severity,
19233                                },
19234                            ),
19235                        );
19236                    }
19237                    inline_diagnostics
19238                })
19239                .await;
19240
19241            editor
19242                .update(cx, |editor, cx| {
19243                    editor.inline_diagnostics = new_inline_diagnostics;
19244                    cx.notify();
19245                })
19246                .ok();
19247        });
19248    }
19249
19250    fn pull_diagnostics(
19251        &mut self,
19252        buffer_id: BufferId,
19253        _window: &Window,
19254        cx: &mut Context<Self>,
19255    ) -> Option<()> {
19256        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
19257            return None;
19258        }
19259        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
19260            .diagnostics
19261            .lsp_pull_diagnostics;
19262        if !pull_diagnostics_settings.enabled {
19263            return None;
19264        }
19265        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
19266        let project = self.project()?.downgrade();
19267        let buffer = self.buffer().read(cx).buffer(buffer_id)?;
19268
19269        self.pull_diagnostics_task = cx.spawn(async move |_, cx| {
19270            cx.background_executor().timer(debounce).await;
19271            if let Ok(task) = project.update(cx, |project, cx| {
19272                project.lsp_store().update(cx, |lsp_store, cx| {
19273                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
19274                })
19275            }) {
19276                task.await.log_err();
19277            }
19278            project
19279                .update(cx, |project, cx| {
19280                    project.lsp_store().update(cx, |lsp_store, cx| {
19281                        lsp_store.pull_document_diagnostics_for_buffer_edit(buffer_id, cx);
19282                    })
19283                })
19284                .log_err();
19285        });
19286
19287        Some(())
19288    }
19289
19290    pub fn set_selections_from_remote(
19291        &mut self,
19292        selections: Vec<Selection<Anchor>>,
19293        pending_selection: Option<Selection<Anchor>>,
19294        window: &mut Window,
19295        cx: &mut Context<Self>,
19296    ) {
19297        let old_cursor_position = self.selections.newest_anchor().head();
19298        self.selections
19299            .change_with(&self.display_snapshot(cx), |s| {
19300                s.select_anchors(selections);
19301                if let Some(pending_selection) = pending_selection {
19302                    s.set_pending(pending_selection, SelectMode::Character);
19303                } else {
19304                    s.clear_pending();
19305                }
19306            });
19307        self.selections_did_change(
19308            false,
19309            &old_cursor_position,
19310            SelectionEffects::default(),
19311            window,
19312            cx,
19313        );
19314    }
19315
19316    pub fn transact(
19317        &mut self,
19318        window: &mut Window,
19319        cx: &mut Context<Self>,
19320        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19321    ) -> Option<TransactionId> {
19322        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19323            this.start_transaction_at(Instant::now(), window, cx);
19324            update(this, window, cx);
19325            this.end_transaction_at(Instant::now(), cx)
19326        })
19327    }
19328
19329    pub fn start_transaction_at(
19330        &mut self,
19331        now: Instant,
19332        window: &mut Window,
19333        cx: &mut Context<Self>,
19334    ) -> Option<TransactionId> {
19335        self.end_selection(window, cx);
19336        if let Some(tx_id) = self
19337            .buffer
19338            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19339        {
19340            self.selection_history
19341                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19342            cx.emit(EditorEvent::TransactionBegun {
19343                transaction_id: tx_id,
19344            });
19345            Some(tx_id)
19346        } else {
19347            None
19348        }
19349    }
19350
19351    pub fn end_transaction_at(
19352        &mut self,
19353        now: Instant,
19354        cx: &mut Context<Self>,
19355    ) -> Option<TransactionId> {
19356        if let Some(transaction_id) = self
19357            .buffer
19358            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19359        {
19360            if let Some((_, end_selections)) =
19361                self.selection_history.transaction_mut(transaction_id)
19362            {
19363                *end_selections = Some(self.selections.disjoint_anchors_arc());
19364            } else {
19365                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19366            }
19367
19368            cx.emit(EditorEvent::Edited { transaction_id });
19369            Some(transaction_id)
19370        } else {
19371            None
19372        }
19373    }
19374
19375    pub fn modify_transaction_selection_history(
19376        &mut self,
19377        transaction_id: TransactionId,
19378        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19379    ) -> bool {
19380        self.selection_history
19381            .transaction_mut(transaction_id)
19382            .map(modify)
19383            .is_some()
19384    }
19385
19386    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19387        if self.selection_mark_mode {
19388            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19389                s.move_with(|_, sel| {
19390                    sel.collapse_to(sel.head(), SelectionGoal::None);
19391                });
19392            })
19393        }
19394        self.selection_mark_mode = true;
19395        cx.notify();
19396    }
19397
19398    pub fn swap_selection_ends(
19399        &mut self,
19400        _: &actions::SwapSelectionEnds,
19401        window: &mut Window,
19402        cx: &mut Context<Self>,
19403    ) {
19404        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19405            s.move_with(|_, sel| {
19406                if sel.start != sel.end {
19407                    sel.reversed = !sel.reversed
19408                }
19409            });
19410        });
19411        self.request_autoscroll(Autoscroll::newest(), cx);
19412        cx.notify();
19413    }
19414
19415    pub fn toggle_focus(
19416        workspace: &mut Workspace,
19417        _: &actions::ToggleFocus,
19418        window: &mut Window,
19419        cx: &mut Context<Workspace>,
19420    ) {
19421        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19422            return;
19423        };
19424        workspace.activate_item(&item, true, true, window, cx);
19425    }
19426
19427    pub fn toggle_fold(
19428        &mut self,
19429        _: &actions::ToggleFold,
19430        window: &mut Window,
19431        cx: &mut Context<Self>,
19432    ) {
19433        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19434            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19435            let selection = self.selections.newest::<Point>(&display_map);
19436
19437            let range = if selection.is_empty() {
19438                let point = selection.head().to_display_point(&display_map);
19439                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19440                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19441                    .to_point(&display_map);
19442                start..end
19443            } else {
19444                selection.range()
19445            };
19446            if display_map.folds_in_range(range).next().is_some() {
19447                self.unfold_lines(&Default::default(), window, cx)
19448            } else {
19449                self.fold(&Default::default(), window, cx)
19450            }
19451        } else {
19452            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19453            let buffer_ids: HashSet<_> = self
19454                .selections
19455                .disjoint_anchor_ranges()
19456                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19457                .collect();
19458
19459            let should_unfold = buffer_ids
19460                .iter()
19461                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19462
19463            for buffer_id in buffer_ids {
19464                if should_unfold {
19465                    self.unfold_buffer(buffer_id, cx);
19466                } else {
19467                    self.fold_buffer(buffer_id, cx);
19468                }
19469            }
19470        }
19471    }
19472
19473    pub fn toggle_fold_recursive(
19474        &mut self,
19475        _: &actions::ToggleFoldRecursive,
19476        window: &mut Window,
19477        cx: &mut Context<Self>,
19478    ) {
19479        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19480
19481        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19482        let range = if selection.is_empty() {
19483            let point = selection.head().to_display_point(&display_map);
19484            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19485            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19486                .to_point(&display_map);
19487            start..end
19488        } else {
19489            selection.range()
19490        };
19491        if display_map.folds_in_range(range).next().is_some() {
19492            self.unfold_recursive(&Default::default(), window, cx)
19493        } else {
19494            self.fold_recursive(&Default::default(), window, cx)
19495        }
19496    }
19497
19498    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19499        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19500            let mut to_fold = Vec::new();
19501            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19502            let selections = self.selections.all_adjusted(&display_map);
19503
19504            for selection in selections {
19505                let range = selection.range().sorted();
19506                let buffer_start_row = range.start.row;
19507
19508                if range.start.row != range.end.row {
19509                    let mut found = false;
19510                    let mut row = range.start.row;
19511                    while row <= range.end.row {
19512                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19513                        {
19514                            found = true;
19515                            row = crease.range().end.row + 1;
19516                            to_fold.push(crease);
19517                        } else {
19518                            row += 1
19519                        }
19520                    }
19521                    if found {
19522                        continue;
19523                    }
19524                }
19525
19526                for row in (0..=range.start.row).rev() {
19527                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19528                        && crease.range().end.row >= buffer_start_row
19529                    {
19530                        to_fold.push(crease);
19531                        if row <= range.start.row {
19532                            break;
19533                        }
19534                    }
19535                }
19536            }
19537
19538            self.fold_creases(to_fold, true, window, cx);
19539        } else {
19540            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19541            let buffer_ids = self
19542                .selections
19543                .disjoint_anchor_ranges()
19544                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19545                .collect::<HashSet<_>>();
19546            for buffer_id in buffer_ids {
19547                self.fold_buffer(buffer_id, cx);
19548            }
19549        }
19550    }
19551
19552    pub fn toggle_fold_all(
19553        &mut self,
19554        _: &actions::ToggleFoldAll,
19555        window: &mut Window,
19556        cx: &mut Context<Self>,
19557    ) {
19558        let has_folds = if self.buffer.read(cx).is_singleton() {
19559            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19560            let has_folds = display_map
19561                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19562                .next()
19563                .is_some();
19564            has_folds
19565        } else {
19566            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19567            let has_folds = buffer_ids
19568                .iter()
19569                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19570            has_folds
19571        };
19572
19573        if has_folds {
19574            self.unfold_all(&actions::UnfoldAll, window, cx);
19575        } else {
19576            self.fold_all(&actions::FoldAll, window, cx);
19577        }
19578    }
19579
19580    fn fold_at_level(
19581        &mut self,
19582        fold_at: &FoldAtLevel,
19583        window: &mut Window,
19584        cx: &mut Context<Self>,
19585    ) {
19586        if !self.buffer.read(cx).is_singleton() {
19587            return;
19588        }
19589
19590        let fold_at_level = fold_at.0;
19591        let snapshot = self.buffer.read(cx).snapshot(cx);
19592        let mut to_fold = Vec::new();
19593        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19594
19595        let row_ranges_to_keep: Vec<Range<u32>> = self
19596            .selections
19597            .all::<Point>(&self.display_snapshot(cx))
19598            .into_iter()
19599            .map(|sel| sel.start.row..sel.end.row)
19600            .collect();
19601
19602        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19603            while start_row < end_row {
19604                match self
19605                    .snapshot(window, cx)
19606                    .crease_for_buffer_row(MultiBufferRow(start_row))
19607                {
19608                    Some(crease) => {
19609                        let nested_start_row = crease.range().start.row + 1;
19610                        let nested_end_row = crease.range().end.row;
19611
19612                        if current_level < fold_at_level {
19613                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19614                        } else if current_level == fold_at_level {
19615                            // Fold iff there is no selection completely contained within the fold region
19616                            if !row_ranges_to_keep.iter().any(|selection| {
19617                                selection.end >= nested_start_row
19618                                    && selection.start <= nested_end_row
19619                            }) {
19620                                to_fold.push(crease);
19621                            }
19622                        }
19623
19624                        start_row = nested_end_row + 1;
19625                    }
19626                    None => start_row += 1,
19627                }
19628            }
19629        }
19630
19631        self.fold_creases(to_fold, true, window, cx);
19632    }
19633
19634    pub fn fold_at_level_1(
19635        &mut self,
19636        _: &actions::FoldAtLevel1,
19637        window: &mut Window,
19638        cx: &mut Context<Self>,
19639    ) {
19640        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19641    }
19642
19643    pub fn fold_at_level_2(
19644        &mut self,
19645        _: &actions::FoldAtLevel2,
19646        window: &mut Window,
19647        cx: &mut Context<Self>,
19648    ) {
19649        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19650    }
19651
19652    pub fn fold_at_level_3(
19653        &mut self,
19654        _: &actions::FoldAtLevel3,
19655        window: &mut Window,
19656        cx: &mut Context<Self>,
19657    ) {
19658        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19659    }
19660
19661    pub fn fold_at_level_4(
19662        &mut self,
19663        _: &actions::FoldAtLevel4,
19664        window: &mut Window,
19665        cx: &mut Context<Self>,
19666    ) {
19667        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19668    }
19669
19670    pub fn fold_at_level_5(
19671        &mut self,
19672        _: &actions::FoldAtLevel5,
19673        window: &mut Window,
19674        cx: &mut Context<Self>,
19675    ) {
19676        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19677    }
19678
19679    pub fn fold_at_level_6(
19680        &mut self,
19681        _: &actions::FoldAtLevel6,
19682        window: &mut Window,
19683        cx: &mut Context<Self>,
19684    ) {
19685        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19686    }
19687
19688    pub fn fold_at_level_7(
19689        &mut self,
19690        _: &actions::FoldAtLevel7,
19691        window: &mut Window,
19692        cx: &mut Context<Self>,
19693    ) {
19694        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19695    }
19696
19697    pub fn fold_at_level_8(
19698        &mut self,
19699        _: &actions::FoldAtLevel8,
19700        window: &mut Window,
19701        cx: &mut Context<Self>,
19702    ) {
19703        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19704    }
19705
19706    pub fn fold_at_level_9(
19707        &mut self,
19708        _: &actions::FoldAtLevel9,
19709        window: &mut Window,
19710        cx: &mut Context<Self>,
19711    ) {
19712        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19713    }
19714
19715    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19716        if self.buffer.read(cx).is_singleton() {
19717            let mut fold_ranges = Vec::new();
19718            let snapshot = self.buffer.read(cx).snapshot(cx);
19719
19720            for row in 0..snapshot.max_row().0 {
19721                if let Some(foldable_range) = self
19722                    .snapshot(window, cx)
19723                    .crease_for_buffer_row(MultiBufferRow(row))
19724                {
19725                    fold_ranges.push(foldable_range);
19726                }
19727            }
19728
19729            self.fold_creases(fold_ranges, true, window, cx);
19730        } else {
19731            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19732                editor
19733                    .update_in(cx, |editor, _, cx| {
19734                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19735                            editor.fold_buffer(buffer_id, cx);
19736                        }
19737                    })
19738                    .ok();
19739            });
19740        }
19741        cx.emit(SearchEvent::ResultsCollapsedChanged(
19742            CollapseDirection::Collapsed,
19743        ));
19744    }
19745
19746    pub fn fold_function_bodies(
19747        &mut self,
19748        _: &actions::FoldFunctionBodies,
19749        window: &mut Window,
19750        cx: &mut Context<Self>,
19751    ) {
19752        let snapshot = self.buffer.read(cx).snapshot(cx);
19753
19754        let ranges = snapshot
19755            .text_object_ranges(
19756                MultiBufferOffset(0)..snapshot.len(),
19757                TreeSitterOptions::default(),
19758            )
19759            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19760            .collect::<Vec<_>>();
19761
19762        let creases = ranges
19763            .into_iter()
19764            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19765            .collect();
19766
19767        self.fold_creases(creases, true, window, cx);
19768    }
19769
19770    pub fn fold_recursive(
19771        &mut self,
19772        _: &actions::FoldRecursive,
19773        window: &mut Window,
19774        cx: &mut Context<Self>,
19775    ) {
19776        let mut to_fold = Vec::new();
19777        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19778        let selections = self.selections.all_adjusted(&display_map);
19779
19780        for selection in selections {
19781            let range = selection.range().sorted();
19782            let buffer_start_row = range.start.row;
19783
19784            if range.start.row != range.end.row {
19785                let mut found = false;
19786                for row in range.start.row..=range.end.row {
19787                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19788                        found = true;
19789                        to_fold.push(crease);
19790                    }
19791                }
19792                if found {
19793                    continue;
19794                }
19795            }
19796
19797            for row in (0..=range.start.row).rev() {
19798                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19799                    if crease.range().end.row >= buffer_start_row {
19800                        to_fold.push(crease);
19801                    } else {
19802                        break;
19803                    }
19804                }
19805            }
19806        }
19807
19808        self.fold_creases(to_fold, true, window, cx);
19809    }
19810
19811    pub fn fold_at(
19812        &mut self,
19813        buffer_row: MultiBufferRow,
19814        window: &mut Window,
19815        cx: &mut Context<Self>,
19816    ) {
19817        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19818
19819        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19820            let autoscroll = self
19821                .selections
19822                .all::<Point>(&display_map)
19823                .iter()
19824                .any(|selection| crease.range().overlaps(&selection.range()));
19825
19826            self.fold_creases(vec![crease], autoscroll, window, cx);
19827        }
19828    }
19829
19830    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19831        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19832            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19833            let buffer = display_map.buffer_snapshot();
19834            let selections = self.selections.all::<Point>(&display_map);
19835            let ranges = selections
19836                .iter()
19837                .map(|s| {
19838                    let range = s.display_range(&display_map).sorted();
19839                    let mut start = range.start.to_point(&display_map);
19840                    let mut end = range.end.to_point(&display_map);
19841                    start.column = 0;
19842                    end.column = buffer.line_len(MultiBufferRow(end.row));
19843                    start..end
19844                })
19845                .collect::<Vec<_>>();
19846
19847            self.unfold_ranges(&ranges, true, true, cx);
19848        } else {
19849            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19850            let buffer_ids = self
19851                .selections
19852                .disjoint_anchor_ranges()
19853                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19854                .collect::<HashSet<_>>();
19855            for buffer_id in buffer_ids {
19856                self.unfold_buffer(buffer_id, cx);
19857            }
19858        }
19859    }
19860
19861    pub fn unfold_recursive(
19862        &mut self,
19863        _: &UnfoldRecursive,
19864        _window: &mut Window,
19865        cx: &mut Context<Self>,
19866    ) {
19867        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19868        let selections = self.selections.all::<Point>(&display_map);
19869        let ranges = selections
19870            .iter()
19871            .map(|s| {
19872                let mut range = s.display_range(&display_map).sorted();
19873                *range.start.column_mut() = 0;
19874                *range.end.column_mut() = display_map.line_len(range.end.row());
19875                let start = range.start.to_point(&display_map);
19876                let end = range.end.to_point(&display_map);
19877                start..end
19878            })
19879            .collect::<Vec<_>>();
19880
19881        self.unfold_ranges(&ranges, true, true, cx);
19882    }
19883
19884    pub fn unfold_at(
19885        &mut self,
19886        buffer_row: MultiBufferRow,
19887        _window: &mut Window,
19888        cx: &mut Context<Self>,
19889    ) {
19890        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19891
19892        let intersection_range = Point::new(buffer_row.0, 0)
19893            ..Point::new(
19894                buffer_row.0,
19895                display_map.buffer_snapshot().line_len(buffer_row),
19896            );
19897
19898        let autoscroll = self
19899            .selections
19900            .all::<Point>(&display_map)
19901            .iter()
19902            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19903
19904        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19905    }
19906
19907    pub fn unfold_all(
19908        &mut self,
19909        _: &actions::UnfoldAll,
19910        _window: &mut Window,
19911        cx: &mut Context<Self>,
19912    ) {
19913        if self.buffer.read(cx).is_singleton() {
19914            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19915            self.unfold_ranges(
19916                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19917                true,
19918                true,
19919                cx,
19920            );
19921        } else {
19922            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19923                editor
19924                    .update(cx, |editor, cx| {
19925                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19926                            editor.unfold_buffer(buffer_id, cx);
19927                        }
19928                    })
19929                    .ok();
19930            });
19931        }
19932        cx.emit(SearchEvent::ResultsCollapsedChanged(
19933            CollapseDirection::Expanded,
19934        ));
19935    }
19936
19937    pub fn fold_selected_ranges(
19938        &mut self,
19939        _: &FoldSelectedRanges,
19940        window: &mut Window,
19941        cx: &mut Context<Self>,
19942    ) {
19943        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19944        let selections = self.selections.all_adjusted(&display_map);
19945        let ranges = selections
19946            .into_iter()
19947            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19948            .collect::<Vec<_>>();
19949        self.fold_creases(ranges, true, window, cx);
19950    }
19951
19952    pub fn fold_ranges<T: ToOffset + Clone>(
19953        &mut self,
19954        ranges: Vec<Range<T>>,
19955        auto_scroll: bool,
19956        window: &mut Window,
19957        cx: &mut Context<Self>,
19958    ) {
19959        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19960        let ranges = ranges
19961            .into_iter()
19962            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19963            .collect::<Vec<_>>();
19964        self.fold_creases(ranges, auto_scroll, window, cx);
19965    }
19966
19967    pub fn fold_creases<T: ToOffset + Clone>(
19968        &mut self,
19969        creases: Vec<Crease<T>>,
19970        auto_scroll: bool,
19971        _window: &mut Window,
19972        cx: &mut Context<Self>,
19973    ) {
19974        if creases.is_empty() {
19975            return;
19976        }
19977
19978        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19979
19980        if auto_scroll {
19981            self.request_autoscroll(Autoscroll::fit(), cx);
19982        }
19983
19984        cx.notify();
19985
19986        self.scrollbar_marker_state.dirty = true;
19987        self.folds_did_change(cx);
19988    }
19989
19990    /// Removes any folds whose ranges intersect any of the given ranges.
19991    pub fn unfold_ranges<T: ToOffset + Clone>(
19992        &mut self,
19993        ranges: &[Range<T>],
19994        inclusive: bool,
19995        auto_scroll: bool,
19996        cx: &mut Context<Self>,
19997    ) {
19998        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19999            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
20000        });
20001        self.folds_did_change(cx);
20002    }
20003
20004    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20005        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
20006            return;
20007        }
20008
20009        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
20010        self.display_map.update(cx, |display_map, cx| {
20011            display_map.fold_buffers([buffer_id], cx)
20012        });
20013
20014        let snapshot = self.display_snapshot(cx);
20015        self.selections.change_with(&snapshot, |selections| {
20016            selections.remove_selections_from_buffer(buffer_id);
20017        });
20018
20019        cx.emit(EditorEvent::BufferFoldToggled {
20020            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
20021            folded: true,
20022        });
20023        cx.notify();
20024    }
20025
20026    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20027        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
20028            return;
20029        }
20030        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
20031        self.display_map.update(cx, |display_map, cx| {
20032            display_map.unfold_buffers([buffer_id], cx);
20033        });
20034        cx.emit(EditorEvent::BufferFoldToggled {
20035            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
20036            folded: false,
20037        });
20038        cx.notify();
20039    }
20040
20041    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
20042        self.display_map.read(cx).is_buffer_folded(buffer)
20043    }
20044
20045    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
20046        self.display_map.read(cx).folded_buffers()
20047    }
20048
20049    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20050        self.display_map.update(cx, |display_map, cx| {
20051            display_map.disable_header_for_buffer(buffer_id, cx);
20052        });
20053        cx.notify();
20054    }
20055
20056    /// Removes any folds with the given ranges.
20057    pub fn remove_folds_with_type<T: ToOffset + Clone>(
20058        &mut self,
20059        ranges: &[Range<T>],
20060        type_id: TypeId,
20061        auto_scroll: bool,
20062        cx: &mut Context<Self>,
20063    ) {
20064        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20065            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
20066        });
20067        self.folds_did_change(cx);
20068    }
20069
20070    fn remove_folds_with<T: ToOffset + Clone>(
20071        &mut self,
20072        ranges: &[Range<T>],
20073        auto_scroll: bool,
20074        cx: &mut Context<Self>,
20075        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
20076    ) {
20077        if ranges.is_empty() {
20078            return;
20079        }
20080
20081        let mut buffers_affected = HashSet::default();
20082        let multi_buffer = self.buffer().read(cx);
20083        for range in ranges {
20084            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
20085                buffers_affected.insert(buffer.read(cx).remote_id());
20086            };
20087        }
20088
20089        self.display_map.update(cx, update);
20090
20091        if auto_scroll {
20092            self.request_autoscroll(Autoscroll::fit(), cx);
20093        }
20094
20095        cx.notify();
20096        self.scrollbar_marker_state.dirty = true;
20097        self.active_indent_guides_state.dirty = true;
20098    }
20099
20100    pub fn update_renderer_widths(
20101        &mut self,
20102        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
20103        cx: &mut Context<Self>,
20104    ) -> bool {
20105        self.display_map
20106            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
20107    }
20108
20109    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
20110        self.display_map.read(cx).fold_placeholder.clone()
20111    }
20112
20113    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
20114        self.buffer.update(cx, |buffer, cx| {
20115            buffer.set_all_diff_hunks_expanded(cx);
20116        });
20117    }
20118
20119    pub fn expand_all_diff_hunks(
20120        &mut self,
20121        _: &ExpandAllDiffHunks,
20122        _window: &mut Window,
20123        cx: &mut Context<Self>,
20124    ) {
20125        self.buffer.update(cx, |buffer, cx| {
20126            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20127        });
20128    }
20129
20130    pub fn collapse_all_diff_hunks(
20131        &mut self,
20132        _: &CollapseAllDiffHunks,
20133        _window: &mut Window,
20134        cx: &mut Context<Self>,
20135    ) {
20136        self.buffer.update(cx, |buffer, cx| {
20137            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20138        });
20139    }
20140
20141    pub fn toggle_selected_diff_hunks(
20142        &mut self,
20143        _: &ToggleSelectedDiffHunks,
20144        _window: &mut Window,
20145        cx: &mut Context<Self>,
20146    ) {
20147        let ranges: Vec<_> = self
20148            .selections
20149            .disjoint_anchors()
20150            .iter()
20151            .map(|s| s.range())
20152            .collect();
20153        self.toggle_diff_hunks_in_ranges(ranges, cx);
20154    }
20155
20156    pub fn diff_hunks_in_ranges<'a>(
20157        &'a self,
20158        ranges: &'a [Range<Anchor>],
20159        buffer: &'a MultiBufferSnapshot,
20160    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
20161        ranges.iter().flat_map(move |range| {
20162            let end_excerpt_id = range.end.excerpt_id;
20163            let range = range.to_point(buffer);
20164            let mut peek_end = range.end;
20165            if range.end.row < buffer.max_row().0 {
20166                peek_end = Point::new(range.end.row + 1, 0);
20167            }
20168            buffer
20169                .diff_hunks_in_range(range.start..peek_end)
20170                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
20171        })
20172    }
20173
20174    pub fn has_stageable_diff_hunks_in_ranges(
20175        &self,
20176        ranges: &[Range<Anchor>],
20177        snapshot: &MultiBufferSnapshot,
20178    ) -> bool {
20179        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
20180        hunks.any(|hunk| hunk.status().has_secondary_hunk())
20181    }
20182
20183    pub fn toggle_staged_selected_diff_hunks(
20184        &mut self,
20185        _: &::git::ToggleStaged,
20186        _: &mut Window,
20187        cx: &mut Context<Self>,
20188    ) {
20189        let snapshot = self.buffer.read(cx).snapshot(cx);
20190        let ranges: Vec<_> = self
20191            .selections
20192            .disjoint_anchors()
20193            .iter()
20194            .map(|s| s.range())
20195            .collect();
20196        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
20197        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20198    }
20199
20200    pub fn set_render_diff_hunk_controls(
20201        &mut self,
20202        render_diff_hunk_controls: RenderDiffHunkControlsFn,
20203        cx: &mut Context<Self>,
20204    ) {
20205        self.render_diff_hunk_controls = render_diff_hunk_controls;
20206        cx.notify();
20207    }
20208
20209    pub fn stage_and_next(
20210        &mut self,
20211        _: &::git::StageAndNext,
20212        window: &mut Window,
20213        cx: &mut Context<Self>,
20214    ) {
20215        self.do_stage_or_unstage_and_next(true, window, cx);
20216    }
20217
20218    pub fn unstage_and_next(
20219        &mut self,
20220        _: &::git::UnstageAndNext,
20221        window: &mut Window,
20222        cx: &mut Context<Self>,
20223    ) {
20224        self.do_stage_or_unstage_and_next(false, window, cx);
20225    }
20226
20227    pub fn stage_or_unstage_diff_hunks(
20228        &mut self,
20229        stage: bool,
20230        ranges: Vec<Range<Anchor>>,
20231        cx: &mut Context<Self>,
20232    ) {
20233        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
20234        cx.spawn(async move |this, cx| {
20235            task.await?;
20236            this.update(cx, |this, cx| {
20237                let snapshot = this.buffer.read(cx).snapshot(cx);
20238                let chunk_by = this
20239                    .diff_hunks_in_ranges(&ranges, &snapshot)
20240                    .chunk_by(|hunk| hunk.buffer_id);
20241                for (buffer_id, hunks) in &chunk_by {
20242                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
20243                }
20244            })
20245        })
20246        .detach_and_log_err(cx);
20247    }
20248
20249    fn save_buffers_for_ranges_if_needed(
20250        &mut self,
20251        ranges: &[Range<Anchor>],
20252        cx: &mut Context<Editor>,
20253    ) -> Task<Result<()>> {
20254        let multibuffer = self.buffer.read(cx);
20255        let snapshot = multibuffer.read(cx);
20256        let buffer_ids: HashSet<_> = ranges
20257            .iter()
20258            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
20259            .collect();
20260        drop(snapshot);
20261
20262        let mut buffers = HashSet::default();
20263        for buffer_id in buffer_ids {
20264            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
20265                let buffer = buffer_entity.read(cx);
20266                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
20267                {
20268                    buffers.insert(buffer_entity);
20269                }
20270            }
20271        }
20272
20273        if let Some(project) = &self.project {
20274            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
20275        } else {
20276            Task::ready(Ok(()))
20277        }
20278    }
20279
20280    fn do_stage_or_unstage_and_next(
20281        &mut self,
20282        stage: bool,
20283        window: &mut Window,
20284        cx: &mut Context<Self>,
20285    ) {
20286        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
20287
20288        if ranges.iter().any(|range| range.start != range.end) {
20289            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20290            return;
20291        }
20292
20293        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20294        let snapshot = self.snapshot(window, cx);
20295        let position = self
20296            .selections
20297            .newest::<Point>(&snapshot.display_snapshot)
20298            .head();
20299        let mut row = snapshot
20300            .buffer_snapshot()
20301            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
20302            .find(|hunk| hunk.row_range.start.0 > position.row)
20303            .map(|hunk| hunk.row_range.start);
20304
20305        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
20306        // Outside of the project diff editor, wrap around to the beginning.
20307        if !all_diff_hunks_expanded {
20308            row = row.or_else(|| {
20309                snapshot
20310                    .buffer_snapshot()
20311                    .diff_hunks_in_range(Point::zero()..position)
20312                    .find(|hunk| hunk.row_range.end.0 < position.row)
20313                    .map(|hunk| hunk.row_range.start)
20314            });
20315        }
20316
20317        if let Some(row) = row {
20318            let destination = Point::new(row.0, 0);
20319            let autoscroll = Autoscroll::center();
20320
20321            self.unfold_ranges(&[destination..destination], false, false, cx);
20322            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
20323                s.select_ranges([destination..destination]);
20324            });
20325        }
20326    }
20327
20328    fn do_stage_or_unstage(
20329        &self,
20330        stage: bool,
20331        buffer_id: BufferId,
20332        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20333        cx: &mut App,
20334    ) -> Option<()> {
20335        let project = self.project()?;
20336        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20337        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20338        let buffer_snapshot = buffer.read(cx).snapshot();
20339        let file_exists = buffer_snapshot
20340            .file()
20341            .is_some_and(|file| file.disk_state().exists());
20342        diff.update(cx, |diff, cx| {
20343            diff.stage_or_unstage_hunks(
20344                stage,
20345                &hunks
20346                    .map(|hunk| buffer_diff::DiffHunk {
20347                        buffer_range: hunk.buffer_range,
20348                        // We don't need to pass in word diffs here because they're only used for rendering and
20349                        // this function changes internal state
20350                        base_word_diffs: Vec::default(),
20351                        buffer_word_diffs: Vec::default(),
20352                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20353                            ..hunk.diff_base_byte_range.end.0,
20354                        secondary_status: hunk.status.secondary,
20355                        range: Point::zero()..Point::zero(), // unused
20356                    })
20357                    .collect::<Vec<_>>(),
20358                &buffer_snapshot,
20359                file_exists,
20360                cx,
20361            )
20362        });
20363        None
20364    }
20365
20366    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20367        let ranges: Vec<_> = self
20368            .selections
20369            .disjoint_anchors()
20370            .iter()
20371            .map(|s| s.range())
20372            .collect();
20373        self.buffer
20374            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20375    }
20376
20377    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20378        self.buffer.update(cx, |buffer, cx| {
20379            let ranges = vec![Anchor::min()..Anchor::max()];
20380            if !buffer.all_diff_hunks_expanded()
20381                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20382            {
20383                buffer.collapse_diff_hunks(ranges, cx);
20384                true
20385            } else {
20386                false
20387            }
20388        })
20389    }
20390
20391    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20392        if self.buffer.read(cx).all_diff_hunks_expanded() {
20393            return true;
20394        }
20395        let ranges = vec![Anchor::min()..Anchor::max()];
20396        self.buffer
20397            .read(cx)
20398            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20399    }
20400
20401    fn toggle_diff_hunks_in_ranges(
20402        &mut self,
20403        ranges: Vec<Range<Anchor>>,
20404        cx: &mut Context<Editor>,
20405    ) {
20406        self.buffer.update(cx, |buffer, cx| {
20407            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20408            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20409        })
20410    }
20411
20412    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20413        self.buffer.update(cx, |buffer, cx| {
20414            let snapshot = buffer.snapshot(cx);
20415            let excerpt_id = range.end.excerpt_id;
20416            let point_range = range.to_point(&snapshot);
20417            let expand = !buffer.single_hunk_is_expanded(range, cx);
20418            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20419        })
20420    }
20421
20422    pub(crate) fn apply_all_diff_hunks(
20423        &mut self,
20424        _: &ApplyAllDiffHunks,
20425        window: &mut Window,
20426        cx: &mut Context<Self>,
20427    ) {
20428        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20429
20430        let buffers = self.buffer.read(cx).all_buffers();
20431        for branch_buffer in buffers {
20432            branch_buffer.update(cx, |branch_buffer, cx| {
20433                branch_buffer.merge_into_base(Vec::new(), cx);
20434            });
20435        }
20436
20437        if let Some(project) = self.project.clone() {
20438            self.save(
20439                SaveOptions {
20440                    format: true,
20441                    autosave: false,
20442                },
20443                project,
20444                window,
20445                cx,
20446            )
20447            .detach_and_log_err(cx);
20448        }
20449    }
20450
20451    pub(crate) fn apply_selected_diff_hunks(
20452        &mut self,
20453        _: &ApplyDiffHunk,
20454        window: &mut Window,
20455        cx: &mut Context<Self>,
20456    ) {
20457        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20458        let snapshot = self.snapshot(window, cx);
20459        let hunks = snapshot.hunks_for_ranges(
20460            self.selections
20461                .all(&snapshot.display_snapshot)
20462                .into_iter()
20463                .map(|selection| selection.range()),
20464        );
20465        let mut ranges_by_buffer = HashMap::default();
20466        self.transact(window, cx, |editor, _window, cx| {
20467            for hunk in hunks {
20468                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20469                    ranges_by_buffer
20470                        .entry(buffer.clone())
20471                        .or_insert_with(Vec::new)
20472                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20473                }
20474            }
20475
20476            for (buffer, ranges) in ranges_by_buffer {
20477                buffer.update(cx, |buffer, cx| {
20478                    buffer.merge_into_base(ranges, cx);
20479                });
20480            }
20481        });
20482
20483        if let Some(project) = self.project.clone() {
20484            self.save(
20485                SaveOptions {
20486                    format: true,
20487                    autosave: false,
20488                },
20489                project,
20490                window,
20491                cx,
20492            )
20493            .detach_and_log_err(cx);
20494        }
20495    }
20496
20497    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20498        if hovered != self.gutter_hovered {
20499            self.gutter_hovered = hovered;
20500            cx.notify();
20501        }
20502    }
20503
20504    pub fn insert_blocks(
20505        &mut self,
20506        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20507        autoscroll: Option<Autoscroll>,
20508        cx: &mut Context<Self>,
20509    ) -> Vec<CustomBlockId> {
20510        let blocks = self
20511            .display_map
20512            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20513        if let Some(autoscroll) = autoscroll {
20514            self.request_autoscroll(autoscroll, cx);
20515        }
20516        cx.notify();
20517        blocks
20518    }
20519
20520    pub fn resize_blocks(
20521        &mut self,
20522        heights: HashMap<CustomBlockId, u32>,
20523        autoscroll: Option<Autoscroll>,
20524        cx: &mut Context<Self>,
20525    ) {
20526        self.display_map
20527            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20528        if let Some(autoscroll) = autoscroll {
20529            self.request_autoscroll(autoscroll, cx);
20530        }
20531        cx.notify();
20532    }
20533
20534    pub fn replace_blocks(
20535        &mut self,
20536        renderers: HashMap<CustomBlockId, RenderBlock>,
20537        autoscroll: Option<Autoscroll>,
20538        cx: &mut Context<Self>,
20539    ) {
20540        self.display_map
20541            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20542        if let Some(autoscroll) = autoscroll {
20543            self.request_autoscroll(autoscroll, cx);
20544        }
20545        cx.notify();
20546    }
20547
20548    pub fn remove_blocks(
20549        &mut self,
20550        block_ids: HashSet<CustomBlockId>,
20551        autoscroll: Option<Autoscroll>,
20552        cx: &mut Context<Self>,
20553    ) {
20554        self.display_map.update(cx, |display_map, cx| {
20555            display_map.remove_blocks(block_ids, cx)
20556        });
20557        if let Some(autoscroll) = autoscroll {
20558            self.request_autoscroll(autoscroll, cx);
20559        }
20560        cx.notify();
20561    }
20562
20563    pub fn row_for_block(
20564        &self,
20565        block_id: CustomBlockId,
20566        cx: &mut Context<Self>,
20567    ) -> Option<DisplayRow> {
20568        self.display_map
20569            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20570    }
20571
20572    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20573        self.focused_block = Some(focused_block);
20574    }
20575
20576    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20577        self.focused_block.take()
20578    }
20579
20580    pub fn insert_creases(
20581        &mut self,
20582        creases: impl IntoIterator<Item = Crease<Anchor>>,
20583        cx: &mut Context<Self>,
20584    ) -> Vec<CreaseId> {
20585        self.display_map
20586            .update(cx, |map, cx| map.insert_creases(creases, cx))
20587    }
20588
20589    pub fn remove_creases(
20590        &mut self,
20591        ids: impl IntoIterator<Item = CreaseId>,
20592        cx: &mut Context<Self>,
20593    ) -> Vec<(CreaseId, Range<Anchor>)> {
20594        self.display_map
20595            .update(cx, |map, cx| map.remove_creases(ids, cx))
20596    }
20597
20598    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20599        self.display_map
20600            .update(cx, |map, cx| map.snapshot(cx))
20601            .longest_row()
20602    }
20603
20604    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20605        self.display_map
20606            .update(cx, |map, cx| map.snapshot(cx))
20607            .max_point()
20608    }
20609
20610    pub fn text(&self, cx: &App) -> String {
20611        self.buffer.read(cx).read(cx).text()
20612    }
20613
20614    pub fn is_empty(&self, cx: &App) -> bool {
20615        self.buffer.read(cx).read(cx).is_empty()
20616    }
20617
20618    pub fn text_option(&self, cx: &App) -> Option<String> {
20619        let text = self.text(cx);
20620        let text = text.trim();
20621
20622        if text.is_empty() {
20623            return None;
20624        }
20625
20626        Some(text.to_string())
20627    }
20628
20629    pub fn set_text(
20630        &mut self,
20631        text: impl Into<Arc<str>>,
20632        window: &mut Window,
20633        cx: &mut Context<Self>,
20634    ) {
20635        self.transact(window, cx, |this, _, cx| {
20636            this.buffer
20637                .read(cx)
20638                .as_singleton()
20639                .expect("you can only call set_text on editors for singleton buffers")
20640                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20641        });
20642    }
20643
20644    pub fn display_text(&self, cx: &mut App) -> String {
20645        self.display_map
20646            .update(cx, |map, cx| map.snapshot(cx))
20647            .text()
20648    }
20649
20650    fn create_minimap(
20651        &self,
20652        minimap_settings: MinimapSettings,
20653        window: &mut Window,
20654        cx: &mut Context<Self>,
20655    ) -> Option<Entity<Self>> {
20656        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20657            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20658    }
20659
20660    fn initialize_new_minimap(
20661        &self,
20662        minimap_settings: MinimapSettings,
20663        window: &mut Window,
20664        cx: &mut Context<Self>,
20665    ) -> Entity<Self> {
20666        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20667        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
20668
20669        let mut minimap = Editor::new_internal(
20670            EditorMode::Minimap {
20671                parent: cx.weak_entity(),
20672            },
20673            self.buffer.clone(),
20674            None,
20675            Some(self.display_map.clone()),
20676            window,
20677            cx,
20678        );
20679        minimap.scroll_manager.clone_state(&self.scroll_manager);
20680        minimap.set_text_style_refinement(TextStyleRefinement {
20681            font_size: Some(MINIMAP_FONT_SIZE),
20682            font_weight: Some(MINIMAP_FONT_WEIGHT),
20683            font_family: Some(MINIMAP_FONT_FAMILY),
20684            ..Default::default()
20685        });
20686        minimap.update_minimap_configuration(minimap_settings, cx);
20687        cx.new(|_| minimap)
20688    }
20689
20690    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20691        let current_line_highlight = minimap_settings
20692            .current_line_highlight
20693            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20694        self.set_current_line_highlight(Some(current_line_highlight));
20695    }
20696
20697    pub fn minimap(&self) -> Option<&Entity<Self>> {
20698        self.minimap
20699            .as_ref()
20700            .filter(|_| self.minimap_visibility.visible())
20701    }
20702
20703    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20704        let mut wrap_guides = smallvec![];
20705
20706        if self.show_wrap_guides == Some(false) {
20707            return wrap_guides;
20708        }
20709
20710        let settings = self.buffer.read(cx).language_settings(cx);
20711        if settings.show_wrap_guides {
20712            match self.soft_wrap_mode(cx) {
20713                SoftWrap::Column(soft_wrap) => {
20714                    wrap_guides.push((soft_wrap as usize, true));
20715                }
20716                SoftWrap::Bounded(soft_wrap) => {
20717                    wrap_guides.push((soft_wrap as usize, true));
20718                }
20719                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20720            }
20721            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20722        }
20723
20724        wrap_guides
20725    }
20726
20727    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20728        let settings = self.buffer.read(cx).language_settings(cx);
20729        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20730        match mode {
20731            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20732                SoftWrap::None
20733            }
20734            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20735            language_settings::SoftWrap::PreferredLineLength => {
20736                SoftWrap::Column(settings.preferred_line_length)
20737            }
20738            language_settings::SoftWrap::Bounded => {
20739                SoftWrap::Bounded(settings.preferred_line_length)
20740            }
20741        }
20742    }
20743
20744    pub fn set_soft_wrap_mode(
20745        &mut self,
20746        mode: language_settings::SoftWrap,
20747        cx: &mut Context<Self>,
20748    ) {
20749        self.soft_wrap_mode_override = Some(mode);
20750        cx.notify();
20751    }
20752
20753    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20754        self.hard_wrap = hard_wrap;
20755        cx.notify();
20756    }
20757
20758    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20759        self.text_style_refinement = Some(style);
20760    }
20761
20762    /// called by the Element so we know what style we were most recently rendered with.
20763    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20764        // We intentionally do not inform the display map about the minimap style
20765        // so that wrapping is not recalculated and stays consistent for the editor
20766        // and its linked minimap.
20767        if !self.mode.is_minimap() {
20768            let font = style.text.font();
20769            let font_size = style.text.font_size.to_pixels(window.rem_size());
20770            let display_map = self
20771                .placeholder_display_map
20772                .as_ref()
20773                .filter(|_| self.is_empty(cx))
20774                .unwrap_or(&self.display_map);
20775
20776            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20777        }
20778        self.style = Some(style);
20779    }
20780
20781    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20782        if self.style.is_none() {
20783            self.style = Some(self.create_style(cx));
20784        }
20785        self.style.as_ref().unwrap()
20786    }
20787
20788    // Called by the element. This method is not designed to be called outside of the editor
20789    // element's layout code because it does not notify when rewrapping is computed synchronously.
20790    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20791        if self.is_empty(cx) {
20792            self.placeholder_display_map
20793                .as_ref()
20794                .map_or(false, |display_map| {
20795                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20796                })
20797        } else {
20798            self.display_map
20799                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20800        }
20801    }
20802
20803    pub fn set_soft_wrap(&mut self) {
20804        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20805    }
20806
20807    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20808        if self.soft_wrap_mode_override.is_some() {
20809            self.soft_wrap_mode_override.take();
20810        } else {
20811            let soft_wrap = match self.soft_wrap_mode(cx) {
20812                SoftWrap::GitDiff => return,
20813                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20814                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20815                    language_settings::SoftWrap::None
20816                }
20817            };
20818            self.soft_wrap_mode_override = Some(soft_wrap);
20819        }
20820        cx.notify();
20821    }
20822
20823    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20824        let Some(workspace) = self.workspace() else {
20825            return;
20826        };
20827        let fs = workspace.read(cx).app_state().fs.clone();
20828        let current_show = TabBarSettings::get_global(cx).show;
20829        update_settings_file(fs, cx, move |setting, _| {
20830            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20831        });
20832    }
20833
20834    pub fn toggle_indent_guides(
20835        &mut self,
20836        _: &ToggleIndentGuides,
20837        _: &mut Window,
20838        cx: &mut Context<Self>,
20839    ) {
20840        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20841            self.buffer
20842                .read(cx)
20843                .language_settings(cx)
20844                .indent_guides
20845                .enabled
20846        });
20847        self.show_indent_guides = Some(!currently_enabled);
20848        cx.notify();
20849    }
20850
20851    fn should_show_indent_guides(&self) -> Option<bool> {
20852        self.show_indent_guides
20853    }
20854
20855    pub fn disable_indent_guides_for_buffer(
20856        &mut self,
20857        buffer_id: BufferId,
20858        cx: &mut Context<Self>,
20859    ) {
20860        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20861        cx.notify();
20862    }
20863
20864    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20865        self.buffers_with_disabled_indent_guides
20866            .contains(&buffer_id)
20867    }
20868
20869    pub fn toggle_line_numbers(
20870        &mut self,
20871        _: &ToggleLineNumbers,
20872        _: &mut Window,
20873        cx: &mut Context<Self>,
20874    ) {
20875        let mut editor_settings = EditorSettings::get_global(cx).clone();
20876        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20877        EditorSettings::override_global(editor_settings, cx);
20878    }
20879
20880    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20881        if let Some(show_line_numbers) = self.show_line_numbers {
20882            return show_line_numbers;
20883        }
20884        EditorSettings::get_global(cx).gutter.line_numbers
20885    }
20886
20887    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
20888        match (
20889            self.use_relative_line_numbers,
20890            EditorSettings::get_global(cx).relative_line_numbers,
20891        ) {
20892            (None, setting) => setting,
20893            (Some(false), _) => RelativeLineNumbers::Disabled,
20894            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20895            (Some(true), _) => RelativeLineNumbers::Enabled,
20896        }
20897    }
20898
20899    pub fn toggle_relative_line_numbers(
20900        &mut self,
20901        _: &ToggleRelativeLineNumbers,
20902        _: &mut Window,
20903        cx: &mut Context<Self>,
20904    ) {
20905        let is_relative = self.relative_line_numbers(cx);
20906        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20907    }
20908
20909    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20910        self.use_relative_line_numbers = is_relative;
20911        cx.notify();
20912    }
20913
20914    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20915        self.show_gutter = show_gutter;
20916        cx.notify();
20917    }
20918
20919    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20920        self.show_scrollbars = ScrollbarAxes {
20921            horizontal: show,
20922            vertical: show,
20923        };
20924        cx.notify();
20925    }
20926
20927    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20928        self.show_scrollbars.vertical = show;
20929        cx.notify();
20930    }
20931
20932    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20933        self.show_scrollbars.horizontal = show;
20934        cx.notify();
20935    }
20936
20937    pub fn set_minimap_visibility(
20938        &mut self,
20939        minimap_visibility: MinimapVisibility,
20940        window: &mut Window,
20941        cx: &mut Context<Self>,
20942    ) {
20943        if self.minimap_visibility != minimap_visibility {
20944            if minimap_visibility.visible() && self.minimap.is_none() {
20945                let minimap_settings = EditorSettings::get_global(cx).minimap;
20946                self.minimap =
20947                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20948            }
20949            self.minimap_visibility = minimap_visibility;
20950            cx.notify();
20951        }
20952    }
20953
20954    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20955        self.set_show_scrollbars(false, cx);
20956        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20957    }
20958
20959    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20960        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20961    }
20962
20963    /// Normally the text in full mode and auto height editors is padded on the
20964    /// left side by roughly half a character width for improved hit testing.
20965    ///
20966    /// Use this method to disable this for cases where this is not wanted (e.g.
20967    /// if you want to align the editor text with some other text above or below)
20968    /// or if you want to add this padding to single-line editors.
20969    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20970        self.offset_content = offset_content;
20971        cx.notify();
20972    }
20973
20974    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20975        self.show_line_numbers = Some(show_line_numbers);
20976        cx.notify();
20977    }
20978
20979    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20980        self.disable_expand_excerpt_buttons = true;
20981        cx.notify();
20982    }
20983
20984    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
20985        self.delegate_expand_excerpts = delegate;
20986    }
20987
20988    pub fn set_scroll_companion(&mut self, companion: Option<WeakEntity<Editor>>) {
20989        self.scroll_companion = companion;
20990    }
20991
20992    pub fn scroll_companion(&self) -> Option<&WeakEntity<Editor>> {
20993        self.scroll_companion.as_ref()
20994    }
20995
20996    pub fn set_on_local_selections_changed(
20997        &mut self,
20998        callback: Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
20999    ) {
21000        self.on_local_selections_changed = callback;
21001    }
21002
21003    pub fn set_suppress_selection_callback(&mut self, suppress: bool) {
21004        self.suppress_selection_callback = suppress;
21005    }
21006
21007    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
21008        self.show_git_diff_gutter = Some(show_git_diff_gutter);
21009        cx.notify();
21010    }
21011
21012    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
21013        self.show_code_actions = Some(show_code_actions);
21014        cx.notify();
21015    }
21016
21017    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
21018        self.show_runnables = Some(show_runnables);
21019        cx.notify();
21020    }
21021
21022    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
21023        self.show_breakpoints = Some(show_breakpoints);
21024        cx.notify();
21025    }
21026
21027    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
21028        self.show_diff_review_button = show;
21029        cx.notify();
21030    }
21031
21032    pub fn show_diff_review_button(&self) -> bool {
21033        self.show_diff_review_button
21034    }
21035
21036    pub fn render_diff_review_button(
21037        &self,
21038        display_row: DisplayRow,
21039        width: Pixels,
21040        cx: &mut Context<Self>,
21041    ) -> impl IntoElement {
21042        let text_color = cx.theme().colors().text;
21043        let icon_color = cx.theme().colors().icon_accent;
21044
21045        h_flex()
21046            .id("diff_review_button")
21047            .cursor_pointer()
21048            .w(width - px(1.))
21049            .h(relative(0.9))
21050            .justify_center()
21051            .rounded_sm()
21052            .border_1()
21053            .border_color(text_color.opacity(0.1))
21054            .bg(text_color.opacity(0.15))
21055            .hover(|s| {
21056                s.bg(icon_color.opacity(0.4))
21057                    .border_color(icon_color.opacity(0.5))
21058            })
21059            .child(Icon::new(IconName::Plus).size(IconSize::Small))
21060            .tooltip(Tooltip::text("Add Review (drag to select multiple lines)"))
21061            .on_mouse_down(
21062                gpui::MouseButton::Left,
21063                cx.listener(move |editor, _event: &gpui::MouseDownEvent, window, cx| {
21064                    editor.start_diff_review_drag(display_row, window, cx);
21065                }),
21066            )
21067    }
21068
21069    pub fn start_diff_review_drag(
21070        &mut self,
21071        display_row: DisplayRow,
21072        window: &mut Window,
21073        cx: &mut Context<Self>,
21074    ) {
21075        let snapshot = self.snapshot(window, cx);
21076        let point = snapshot
21077            .display_snapshot
21078            .display_point_to_point(DisplayPoint::new(display_row, 0), Bias::Left);
21079        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21080        self.diff_review_drag_state = Some(DiffReviewDragState {
21081            start_anchor: anchor,
21082            current_anchor: anchor,
21083        });
21084        cx.notify();
21085    }
21086
21087    pub fn update_diff_review_drag(
21088        &mut self,
21089        display_row: DisplayRow,
21090        window: &mut Window,
21091        cx: &mut Context<Self>,
21092    ) {
21093        if self.diff_review_drag_state.is_none() {
21094            return;
21095        }
21096        let snapshot = self.snapshot(window, cx);
21097        let point = snapshot
21098            .display_snapshot
21099            .display_point_to_point(display_row.as_display_point(), Bias::Left);
21100        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21101        if let Some(drag_state) = &mut self.diff_review_drag_state {
21102            drag_state.current_anchor = anchor;
21103            cx.notify();
21104        }
21105    }
21106
21107    pub fn end_diff_review_drag(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21108        if let Some(drag_state) = self.diff_review_drag_state.take() {
21109            let snapshot = self.snapshot(window, cx);
21110            let range = drag_state.row_range(&snapshot.display_snapshot);
21111            self.show_diff_review_overlay(*range.start()..*range.end(), window, cx);
21112        }
21113        cx.notify();
21114    }
21115
21116    pub fn cancel_diff_review_drag(&mut self, cx: &mut Context<Self>) {
21117        self.diff_review_drag_state = None;
21118        cx.notify();
21119    }
21120
21121    /// Calculates the appropriate block height for the diff review overlay.
21122    /// Height is in lines: 2 for input row, 1 for header when comments exist,
21123    /// and 2 lines per comment when expanded.
21124    fn calculate_overlay_height(
21125        &self,
21126        hunk_key: &DiffHunkKey,
21127        comments_expanded: bool,
21128        snapshot: &MultiBufferSnapshot,
21129    ) -> u32 {
21130        let comment_count = self.hunk_comment_count(hunk_key, snapshot);
21131        let base_height: u32 = 2; // Input row with avatar and buttons
21132
21133        if comment_count == 0 {
21134            base_height
21135        } else if comments_expanded {
21136            // Header (1 line) + 2 lines per comment
21137            base_height + 1 + (comment_count as u32 * 2)
21138        } else {
21139            // Just header when collapsed
21140            base_height + 1
21141        }
21142    }
21143
21144    pub fn show_diff_review_overlay(
21145        &mut self,
21146        display_range: Range<DisplayRow>,
21147        window: &mut Window,
21148        cx: &mut Context<Self>,
21149    ) {
21150        let Range { start, end } = display_range.sorted();
21151
21152        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21153        let editor_snapshot = self.snapshot(window, cx);
21154
21155        // Convert display rows to multibuffer points
21156        let start_point = editor_snapshot
21157            .display_snapshot
21158            .display_point_to_point(start.as_display_point(), Bias::Left);
21159        let end_point = editor_snapshot
21160            .display_snapshot
21161            .display_point_to_point(end.as_display_point(), Bias::Left);
21162        let end_multi_buffer_row = MultiBufferRow(end_point.row);
21163
21164        // Create anchor range for the selected lines (start of first line to end of last line)
21165        let line_end = Point::new(
21166            end_point.row,
21167            buffer_snapshot.line_len(end_multi_buffer_row),
21168        );
21169        let anchor_range =
21170            buffer_snapshot.anchor_after(start_point)..buffer_snapshot.anchor_before(line_end);
21171
21172        // Compute the hunk key for this display row
21173        let file_path = buffer_snapshot
21174            .file_at(start_point)
21175            .map(|file: &Arc<dyn language::File>| file.path().clone())
21176            .unwrap_or_else(|| Arc::from(util::rel_path::RelPath::empty()));
21177        let hunk_start_anchor = buffer_snapshot.anchor_before(start_point);
21178        let new_hunk_key = DiffHunkKey {
21179            file_path,
21180            hunk_start_anchor,
21181        };
21182
21183        // Check if we already have an overlay for this hunk
21184        if let Some(existing_overlay) = self.diff_review_overlays.iter().find(|overlay| {
21185            Self::hunk_keys_match(&overlay.hunk_key, &new_hunk_key, &buffer_snapshot)
21186        }) {
21187            // Just focus the existing overlay's prompt editor
21188            let focus_handle = existing_overlay.prompt_editor.focus_handle(cx);
21189            window.focus(&focus_handle, cx);
21190            return;
21191        }
21192
21193        // Dismiss overlays that have no comments for their hunks
21194        self.dismiss_overlays_without_comments(cx);
21195
21196        // Get the current user's avatar URI from the project's user_store
21197        let user_avatar_uri = self.project.as_ref().and_then(|project| {
21198            let user_store = project.read(cx).user_store();
21199            user_store
21200                .read(cx)
21201                .current_user()
21202                .map(|user| user.avatar_uri.clone())
21203        });
21204
21205        // Create anchor at the end of the last row so the block appears immediately below it
21206        // Use multibuffer coordinates for anchor creation
21207        let line_len = buffer_snapshot.line_len(end_multi_buffer_row);
21208        let anchor = buffer_snapshot.anchor_after(Point::new(end_multi_buffer_row.0, line_len));
21209
21210        // Use the hunk key we already computed
21211        let hunk_key = new_hunk_key;
21212
21213        // Create the prompt editor for the review input
21214        let prompt_editor = cx.new(|cx| {
21215            let mut editor = Editor::single_line(window, cx);
21216            editor.set_placeholder_text("Add a review comment...", window, cx);
21217            editor
21218        });
21219
21220        // Register the Newline action on the prompt editor to submit the review
21221        let parent_editor = cx.entity().downgrade();
21222        let subscription = prompt_editor.update(cx, |prompt_editor, _cx| {
21223            prompt_editor.register_action({
21224                let parent_editor = parent_editor.clone();
21225                move |_: &crate::actions::Newline, window, cx| {
21226                    if let Some(editor) = parent_editor.upgrade() {
21227                        editor.update(cx, |editor, cx| {
21228                            editor.submit_diff_review_comment(window, cx);
21229                        });
21230                    }
21231                }
21232            })
21233        });
21234
21235        // Calculate initial height based on existing comments for this hunk
21236        let initial_height = self.calculate_overlay_height(&hunk_key, true, &buffer_snapshot);
21237
21238        // Create the overlay block
21239        let prompt_editor_for_render = prompt_editor.clone();
21240        let hunk_key_for_render = hunk_key.clone();
21241        let editor_handle = cx.entity().downgrade();
21242        let block = BlockProperties {
21243            style: BlockStyle::Sticky,
21244            placement: BlockPlacement::Below(anchor),
21245            height: Some(initial_height),
21246            render: Arc::new(move |cx| {
21247                Self::render_diff_review_overlay(
21248                    &prompt_editor_for_render,
21249                    &hunk_key_for_render,
21250                    &editor_handle,
21251                    cx,
21252                )
21253            }),
21254            priority: 0,
21255        };
21256
21257        let block_ids = self.insert_blocks([block], None, cx);
21258        let Some(block_id) = block_ids.into_iter().next() else {
21259            log::error!("Failed to insert diff review overlay block");
21260            return;
21261        };
21262
21263        self.diff_review_overlays.push(DiffReviewOverlay {
21264            anchor_range,
21265            block_id,
21266            prompt_editor: prompt_editor.clone(),
21267            hunk_key,
21268            comments_expanded: true,
21269            inline_edit_editors: HashMap::default(),
21270            inline_edit_subscriptions: HashMap::default(),
21271            user_avatar_uri,
21272            _subscription: subscription,
21273        });
21274
21275        // Focus the prompt editor
21276        let focus_handle = prompt_editor.focus_handle(cx);
21277        window.focus(&focus_handle, cx);
21278
21279        cx.notify();
21280    }
21281
21282    /// Dismisses all diff review overlays.
21283    pub fn dismiss_all_diff_review_overlays(&mut self, cx: &mut Context<Self>) {
21284        if self.diff_review_overlays.is_empty() {
21285            return;
21286        }
21287        let block_ids: HashSet<_> = self
21288            .diff_review_overlays
21289            .drain(..)
21290            .map(|overlay| overlay.block_id)
21291            .collect();
21292        self.remove_blocks(block_ids, None, cx);
21293        cx.notify();
21294    }
21295
21296    /// Dismisses overlays that have no comments stored for their hunks.
21297    /// Keeps overlays that have at least one comment.
21298    fn dismiss_overlays_without_comments(&mut self, cx: &mut Context<Self>) {
21299        let snapshot = self.buffer.read(cx).snapshot(cx);
21300
21301        // First, compute which overlays have comments (to avoid borrow issues with retain)
21302        let overlays_with_comments: Vec<bool> = self
21303            .diff_review_overlays
21304            .iter()
21305            .map(|overlay| self.hunk_comment_count(&overlay.hunk_key, &snapshot) > 0)
21306            .collect();
21307
21308        // Now collect block IDs to remove and retain overlays
21309        let mut block_ids_to_remove = HashSet::default();
21310        let mut index = 0;
21311        self.diff_review_overlays.retain(|overlay| {
21312            let has_comments = overlays_with_comments[index];
21313            index += 1;
21314            if !has_comments {
21315                block_ids_to_remove.insert(overlay.block_id);
21316            }
21317            has_comments
21318        });
21319
21320        if !block_ids_to_remove.is_empty() {
21321            self.remove_blocks(block_ids_to_remove, None, cx);
21322            cx.notify();
21323        }
21324    }
21325
21326    /// Refreshes the diff review overlay block to update its height and render function.
21327    /// Uses resize_blocks and replace_blocks to avoid visual flicker from remove+insert.
21328    fn refresh_diff_review_overlay_height(
21329        &mut self,
21330        hunk_key: &DiffHunkKey,
21331        _window: &mut Window,
21332        cx: &mut Context<Self>,
21333    ) {
21334        // Extract all needed data from overlay first to avoid borrow conflicts
21335        let snapshot = self.buffer.read(cx).snapshot(cx);
21336        let (comments_expanded, block_id, prompt_editor) = {
21337            let Some(overlay) = self
21338                .diff_review_overlays
21339                .iter()
21340                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
21341            else {
21342                return;
21343            };
21344
21345            (
21346                overlay.comments_expanded,
21347                overlay.block_id,
21348                overlay.prompt_editor.clone(),
21349            )
21350        };
21351
21352        // Calculate new height
21353        let snapshot = self.buffer.read(cx).snapshot(cx);
21354        let new_height = self.calculate_overlay_height(hunk_key, comments_expanded, &snapshot);
21355
21356        // Update the block height using resize_blocks (avoids flicker)
21357        let mut heights = HashMap::default();
21358        heights.insert(block_id, new_height);
21359        self.resize_blocks(heights, None, cx);
21360
21361        // Update the render function using replace_blocks (avoids flicker)
21362        let hunk_key_for_render = hunk_key.clone();
21363        let editor_handle = cx.entity().downgrade();
21364        let render: Arc<dyn Fn(&mut BlockContext) -> AnyElement + Send + Sync> =
21365            Arc::new(move |cx| {
21366                Self::render_diff_review_overlay(
21367                    &prompt_editor,
21368                    &hunk_key_for_render,
21369                    &editor_handle,
21370                    cx,
21371                )
21372            });
21373
21374        let mut renderers = HashMap::default();
21375        renderers.insert(block_id, render);
21376        self.replace_blocks(renderers, None, cx);
21377    }
21378
21379    /// Action handler for SubmitDiffReviewComment.
21380    pub fn submit_diff_review_comment_action(
21381        &mut self,
21382        _: &SubmitDiffReviewComment,
21383        window: &mut Window,
21384        cx: &mut Context<Self>,
21385    ) {
21386        self.submit_diff_review_comment(window, cx);
21387    }
21388
21389    /// Stores the diff review comment locally.
21390    /// Comments are stored per-hunk and can later be batch-submitted to the Agent panel.
21391    pub fn submit_diff_review_comment(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21392        // Find the overlay that currently has focus
21393        let overlay_index = self
21394            .diff_review_overlays
21395            .iter()
21396            .position(|overlay| overlay.prompt_editor.focus_handle(cx).is_focused(window));
21397        let Some(overlay_index) = overlay_index else {
21398            return;
21399        };
21400        let overlay = &self.diff_review_overlays[overlay_index];
21401
21402        let comment_text = overlay.prompt_editor.read(cx).text(cx).trim().to_string();
21403        if comment_text.is_empty() {
21404            return;
21405        }
21406
21407        let anchor_range = overlay.anchor_range.clone();
21408        let hunk_key = overlay.hunk_key.clone();
21409
21410        self.add_review_comment(hunk_key.clone(), comment_text, anchor_range, cx);
21411
21412        // Clear the prompt editor but keep the overlay open
21413        if let Some(overlay) = self.diff_review_overlays.get(overlay_index) {
21414            overlay.prompt_editor.update(cx, |editor, cx| {
21415                editor.clear(window, cx);
21416            });
21417        }
21418
21419        // Refresh the overlay to update the block height for the new comment
21420        self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
21421
21422        cx.notify();
21423    }
21424
21425    /// Returns the prompt editor for the diff review overlay, if one is active.
21426    /// This is primarily used for testing.
21427    pub fn diff_review_prompt_editor(&self) -> Option<&Entity<Editor>> {
21428        self.diff_review_overlays
21429            .first()
21430            .map(|overlay| &overlay.prompt_editor)
21431    }
21432
21433    /// Returns the line range for the first diff review overlay, if one is active.
21434    /// Returns (start_row, end_row) as physical line numbers in the underlying file.
21435    pub fn diff_review_line_range(&self, cx: &App) -> Option<(u32, u32)> {
21436        let overlay = self.diff_review_overlays.first()?;
21437        let snapshot = self.buffer.read(cx).snapshot(cx);
21438        let start_point = overlay.anchor_range.start.to_point(&snapshot);
21439        let end_point = overlay.anchor_range.end.to_point(&snapshot);
21440        let start_row = snapshot
21441            .point_to_buffer_point(start_point)
21442            .map(|(_, p, _)| p.row)
21443            .unwrap_or(start_point.row);
21444        let end_row = snapshot
21445            .point_to_buffer_point(end_point)
21446            .map(|(_, p, _)| p.row)
21447            .unwrap_or(end_point.row);
21448        Some((start_row, end_row))
21449    }
21450
21451    /// Sets whether the comments section is expanded in the diff review overlay.
21452    /// This is primarily used for testing.
21453    pub fn set_diff_review_comments_expanded(&mut self, expanded: bool, cx: &mut Context<Self>) {
21454        for overlay in &mut self.diff_review_overlays {
21455            overlay.comments_expanded = expanded;
21456        }
21457        cx.notify();
21458    }
21459
21460    /// Compares two DiffHunkKeys for equality by resolving their anchors.
21461    fn hunk_keys_match(a: &DiffHunkKey, b: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> bool {
21462        a.file_path == b.file_path
21463            && a.hunk_start_anchor.to_point(snapshot) == b.hunk_start_anchor.to_point(snapshot)
21464    }
21465
21466    /// Returns comments for a specific hunk, ordered by creation time.
21467    pub fn comments_for_hunk<'a>(
21468        &'a self,
21469        key: &DiffHunkKey,
21470        snapshot: &MultiBufferSnapshot,
21471    ) -> &'a [StoredReviewComment] {
21472        let key_point = key.hunk_start_anchor.to_point(snapshot);
21473        self.stored_review_comments
21474            .iter()
21475            .find(|(k, _)| {
21476                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
21477            })
21478            .map(|(_, comments)| comments.as_slice())
21479            .unwrap_or(&[])
21480    }
21481
21482    /// Returns the total count of stored review comments across all hunks.
21483    pub fn total_review_comment_count(&self) -> usize {
21484        self.stored_review_comments
21485            .iter()
21486            .map(|(_, v)| v.len())
21487            .sum()
21488    }
21489
21490    /// Returns the count of comments for a specific hunk.
21491    pub fn hunk_comment_count(&self, key: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> usize {
21492        let key_point = key.hunk_start_anchor.to_point(snapshot);
21493        self.stored_review_comments
21494            .iter()
21495            .find(|(k, _)| {
21496                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
21497            })
21498            .map(|(_, v)| v.len())
21499            .unwrap_or(0)
21500    }
21501
21502    /// Adds a new review comment to a specific hunk.
21503    pub fn add_review_comment(
21504        &mut self,
21505        hunk_key: DiffHunkKey,
21506        comment: String,
21507        anchor_range: Range<Anchor>,
21508        cx: &mut Context<Self>,
21509    ) -> usize {
21510        let id = self.next_review_comment_id;
21511        self.next_review_comment_id += 1;
21512
21513        let stored_comment = StoredReviewComment::new(id, comment, anchor_range);
21514
21515        let snapshot = self.buffer.read(cx).snapshot(cx);
21516        let key_point = hunk_key.hunk_start_anchor.to_point(&snapshot);
21517
21518        // Find existing entry for this hunk or add a new one
21519        if let Some((_, comments)) = self.stored_review_comments.iter_mut().find(|(k, _)| {
21520            k.file_path == hunk_key.file_path
21521                && k.hunk_start_anchor.to_point(&snapshot) == key_point
21522        }) {
21523            comments.push(stored_comment);
21524        } else {
21525            self.stored_review_comments
21526                .push((hunk_key, vec![stored_comment]));
21527        }
21528
21529        cx.emit(EditorEvent::ReviewCommentsChanged {
21530            total_count: self.total_review_comment_count(),
21531        });
21532        cx.notify();
21533        id
21534    }
21535
21536    /// Removes a review comment by ID from any hunk.
21537    pub fn remove_review_comment(&mut self, id: usize, cx: &mut Context<Self>) -> bool {
21538        for (_, comments) in self.stored_review_comments.iter_mut() {
21539            if let Some(index) = comments.iter().position(|c| c.id == id) {
21540                comments.remove(index);
21541                cx.emit(EditorEvent::ReviewCommentsChanged {
21542                    total_count: self.total_review_comment_count(),
21543                });
21544                cx.notify();
21545                return true;
21546            }
21547        }
21548        false
21549    }
21550
21551    /// Updates a review comment's text by ID.
21552    pub fn update_review_comment(
21553        &mut self,
21554        id: usize,
21555        new_comment: String,
21556        cx: &mut Context<Self>,
21557    ) -> bool {
21558        for (_, comments) in self.stored_review_comments.iter_mut() {
21559            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
21560                comment.comment = new_comment;
21561                comment.is_editing = false;
21562                cx.emit(EditorEvent::ReviewCommentsChanged {
21563                    total_count: self.total_review_comment_count(),
21564                });
21565                cx.notify();
21566                return true;
21567            }
21568        }
21569        false
21570    }
21571
21572    /// Sets a comment's editing state.
21573    pub fn set_comment_editing(&mut self, id: usize, is_editing: bool, cx: &mut Context<Self>) {
21574        for (_, comments) in self.stored_review_comments.iter_mut() {
21575            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
21576                comment.is_editing = is_editing;
21577                cx.notify();
21578                return;
21579            }
21580        }
21581    }
21582
21583    /// Takes all stored comments from all hunks, clearing the storage.
21584    /// Returns a Vec of (hunk_key, comments) pairs.
21585    pub fn take_all_review_comments(
21586        &mut self,
21587        cx: &mut Context<Self>,
21588    ) -> Vec<(DiffHunkKey, Vec<StoredReviewComment>)> {
21589        // Dismiss all overlays when taking comments (e.g., when sending to agent)
21590        self.dismiss_all_diff_review_overlays(cx);
21591        let comments = std::mem::take(&mut self.stored_review_comments);
21592        // Reset the ID counter since all comments have been taken
21593        self.next_review_comment_id = 0;
21594        cx.emit(EditorEvent::ReviewCommentsChanged { total_count: 0 });
21595        cx.notify();
21596        comments
21597    }
21598
21599    /// Removes review comments whose anchors are no longer valid or whose
21600    /// associated diff hunks no longer exist.
21601    ///
21602    /// This should be called when the buffer changes to prevent orphaned comments
21603    /// from accumulating.
21604    pub fn cleanup_orphaned_review_comments(&mut self, cx: &mut Context<Self>) {
21605        let snapshot = self.buffer.read(cx).snapshot(cx);
21606        let original_count = self.total_review_comment_count();
21607
21608        // Remove comments with invalid hunk anchors
21609        self.stored_review_comments
21610            .retain(|(hunk_key, _)| hunk_key.hunk_start_anchor.is_valid(&snapshot));
21611
21612        // Also clean up individual comments with invalid anchor ranges
21613        for (_, comments) in &mut self.stored_review_comments {
21614            comments.retain(|comment| {
21615                comment.range.start.is_valid(&snapshot) && comment.range.end.is_valid(&snapshot)
21616            });
21617        }
21618
21619        // Remove empty hunk entries
21620        self.stored_review_comments
21621            .retain(|(_, comments)| !comments.is_empty());
21622
21623        let new_count = self.total_review_comment_count();
21624        if new_count != original_count {
21625            cx.emit(EditorEvent::ReviewCommentsChanged {
21626                total_count: new_count,
21627            });
21628            cx.notify();
21629        }
21630    }
21631
21632    /// Toggles the expanded state of the comments section in the overlay.
21633    pub fn toggle_review_comments_expanded(
21634        &mut self,
21635        _: &ToggleReviewCommentsExpanded,
21636        window: &mut Window,
21637        cx: &mut Context<Self>,
21638    ) {
21639        // Find the overlay that currently has focus, or use the first one
21640        let overlay_info = self.diff_review_overlays.iter_mut().find_map(|overlay| {
21641            if overlay.prompt_editor.focus_handle(cx).is_focused(window) {
21642                overlay.comments_expanded = !overlay.comments_expanded;
21643                Some(overlay.hunk_key.clone())
21644            } else {
21645                None
21646            }
21647        });
21648
21649        // If no focused overlay found, toggle the first one
21650        let hunk_key = overlay_info.or_else(|| {
21651            self.diff_review_overlays.first_mut().map(|overlay| {
21652                overlay.comments_expanded = !overlay.comments_expanded;
21653                overlay.hunk_key.clone()
21654            })
21655        });
21656
21657        if let Some(hunk_key) = hunk_key {
21658            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
21659            cx.notify();
21660        }
21661    }
21662
21663    /// Handles the EditReviewComment action - sets a comment into editing mode.
21664    pub fn edit_review_comment(
21665        &mut self,
21666        action: &EditReviewComment,
21667        window: &mut Window,
21668        cx: &mut Context<Self>,
21669    ) {
21670        let comment_id = action.id;
21671
21672        // Set the comment to editing mode
21673        self.set_comment_editing(comment_id, true, cx);
21674
21675        // Find the overlay that contains this comment and create an inline editor if needed
21676        // First, find which hunk this comment belongs to
21677        let hunk_key = self
21678            .stored_review_comments
21679            .iter()
21680            .find_map(|(key, comments)| {
21681                if comments.iter().any(|c| c.id == comment_id) {
21682                    Some(key.clone())
21683                } else {
21684                    None
21685                }
21686            });
21687
21688        let snapshot = self.buffer.read(cx).snapshot(cx);
21689        if let Some(hunk_key) = hunk_key {
21690            if let Some(overlay) = self
21691                .diff_review_overlays
21692                .iter_mut()
21693                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
21694            {
21695                if let std::collections::hash_map::Entry::Vacant(entry) =
21696                    overlay.inline_edit_editors.entry(comment_id)
21697                {
21698                    // Find the comment text
21699                    let comment_text = self
21700                        .stored_review_comments
21701                        .iter()
21702                        .flat_map(|(_, comments)| comments)
21703                        .find(|c| c.id == comment_id)
21704                        .map(|c| c.comment.clone())
21705                        .unwrap_or_default();
21706
21707                    // Create inline editor
21708                    let parent_editor = cx.entity().downgrade();
21709                    let inline_editor = cx.new(|cx| {
21710                        let mut editor = Editor::single_line(window, cx);
21711                        editor.set_text(&*comment_text, window, cx);
21712                        // Select all text for easy replacement
21713                        editor.select_all(&crate::actions::SelectAll, window, cx);
21714                        editor
21715                    });
21716
21717                    // Register the Newline action to confirm the edit
21718                    let subscription = inline_editor.update(cx, |inline_editor, _cx| {
21719                        inline_editor.register_action({
21720                            let parent_editor = parent_editor.clone();
21721                            move |_: &crate::actions::Newline, window, cx| {
21722                                if let Some(editor) = parent_editor.upgrade() {
21723                                    editor.update(cx, |editor, cx| {
21724                                        editor.confirm_edit_review_comment(comment_id, window, cx);
21725                                    });
21726                                }
21727                            }
21728                        })
21729                    });
21730
21731                    // Store the subscription to keep the action handler alive
21732                    overlay
21733                        .inline_edit_subscriptions
21734                        .insert(comment_id, subscription);
21735
21736                    // Focus the inline editor
21737                    let focus_handle = inline_editor.focus_handle(cx);
21738                    window.focus(&focus_handle, cx);
21739
21740                    entry.insert(inline_editor);
21741                }
21742            }
21743        }
21744
21745        cx.notify();
21746    }
21747
21748    /// Confirms an inline edit of a review comment.
21749    pub fn confirm_edit_review_comment(
21750        &mut self,
21751        comment_id: usize,
21752        _window: &mut Window,
21753        cx: &mut Context<Self>,
21754    ) {
21755        // Get the new text from the inline editor
21756        // Find the overlay containing this comment's inline editor
21757        let snapshot = self.buffer.read(cx).snapshot(cx);
21758        let hunk_key = self
21759            .stored_review_comments
21760            .iter()
21761            .find_map(|(key, comments)| {
21762                if comments.iter().any(|c| c.id == comment_id) {
21763                    Some(key.clone())
21764                } else {
21765                    None
21766                }
21767            });
21768
21769        let new_text = hunk_key
21770            .as_ref()
21771            .and_then(|hunk_key| {
21772                self.diff_review_overlays
21773                    .iter()
21774                    .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
21775            })
21776            .as_ref()
21777            .and_then(|overlay| overlay.inline_edit_editors.get(&comment_id))
21778            .map(|editor| editor.read(cx).text(cx).trim().to_string());
21779
21780        if let Some(new_text) = new_text {
21781            if !new_text.is_empty() {
21782                self.update_review_comment(comment_id, new_text, cx);
21783            }
21784        }
21785
21786        // Remove the inline editor and its subscription
21787        if let Some(hunk_key) = hunk_key {
21788            if let Some(overlay) = self
21789                .diff_review_overlays
21790                .iter_mut()
21791                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
21792            {
21793                overlay.inline_edit_editors.remove(&comment_id);
21794                overlay.inline_edit_subscriptions.remove(&comment_id);
21795            }
21796        }
21797
21798        // Clear editing state
21799        self.set_comment_editing(comment_id, false, cx);
21800    }
21801
21802    /// Cancels an inline edit of a review comment.
21803    pub fn cancel_edit_review_comment(
21804        &mut self,
21805        comment_id: usize,
21806        _window: &mut Window,
21807        cx: &mut Context<Self>,
21808    ) {
21809        // Find which hunk this comment belongs to
21810        let hunk_key = self
21811            .stored_review_comments
21812            .iter()
21813            .find_map(|(key, comments)| {
21814                if comments.iter().any(|c| c.id == comment_id) {
21815                    Some(key.clone())
21816                } else {
21817                    None
21818                }
21819            });
21820
21821        // Remove the inline editor and its subscription
21822        if let Some(hunk_key) = hunk_key {
21823            let snapshot = self.buffer.read(cx).snapshot(cx);
21824            if let Some(overlay) = self
21825                .diff_review_overlays
21826                .iter_mut()
21827                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
21828            {
21829                overlay.inline_edit_editors.remove(&comment_id);
21830                overlay.inline_edit_subscriptions.remove(&comment_id);
21831            }
21832        }
21833
21834        // Clear editing state
21835        self.set_comment_editing(comment_id, false, cx);
21836    }
21837
21838    /// Action handler for ConfirmEditReviewComment.
21839    pub fn confirm_edit_review_comment_action(
21840        &mut self,
21841        action: &ConfirmEditReviewComment,
21842        window: &mut Window,
21843        cx: &mut Context<Self>,
21844    ) {
21845        self.confirm_edit_review_comment(action.id, window, cx);
21846    }
21847
21848    /// Action handler for CancelEditReviewComment.
21849    pub fn cancel_edit_review_comment_action(
21850        &mut self,
21851        action: &CancelEditReviewComment,
21852        window: &mut Window,
21853        cx: &mut Context<Self>,
21854    ) {
21855        self.cancel_edit_review_comment(action.id, window, cx);
21856    }
21857
21858    /// Handles the DeleteReviewComment action - removes a comment.
21859    pub fn delete_review_comment(
21860        &mut self,
21861        action: &DeleteReviewComment,
21862        window: &mut Window,
21863        cx: &mut Context<Self>,
21864    ) {
21865        // Get the hunk key before removing the comment
21866        // Find the hunk key from the comment itself
21867        let comment_id = action.id;
21868        let hunk_key = self
21869            .stored_review_comments
21870            .iter()
21871            .find_map(|(key, comments)| {
21872                if comments.iter().any(|c| c.id == comment_id) {
21873                    Some(key.clone())
21874                } else {
21875                    None
21876                }
21877            });
21878
21879        // Also get it from the overlay for refresh purposes
21880        let overlay_hunk_key = self
21881            .diff_review_overlays
21882            .first()
21883            .map(|o| o.hunk_key.clone());
21884
21885        self.remove_review_comment(action.id, cx);
21886
21887        // Refresh the overlay height after removing a comment
21888        if let Some(hunk_key) = hunk_key.or(overlay_hunk_key) {
21889            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
21890        }
21891    }
21892
21893    fn render_diff_review_overlay(
21894        prompt_editor: &Entity<Editor>,
21895        hunk_key: &DiffHunkKey,
21896        editor_handle: &WeakEntity<Editor>,
21897        cx: &mut BlockContext,
21898    ) -> AnyElement {
21899        fn format_line_ranges(ranges: &[(u32, u32)]) -> Option<String> {
21900            if ranges.is_empty() {
21901                return None;
21902            }
21903            let formatted: Vec<String> = ranges
21904                .iter()
21905                .map(|(start, end)| {
21906                    let start_line = start + 1;
21907                    let end_line = end + 1;
21908                    if start_line == end_line {
21909                        format!("Line {start_line}")
21910                    } else {
21911                        format!("Lines {start_line}-{end_line}")
21912                    }
21913                })
21914                .collect();
21915            // Don't show label for single line in single excerpt
21916            if ranges.len() == 1 && ranges[0].0 == ranges[0].1 {
21917                return None;
21918            }
21919            Some(formatted.join(""))
21920        }
21921
21922        let theme = cx.theme();
21923        let colors = theme.colors();
21924
21925        let (comments, comments_expanded, inline_editors, user_avatar_uri, line_ranges) =
21926            editor_handle
21927                .upgrade()
21928                .map(|editor| {
21929                    let editor = editor.read(cx);
21930                    let snapshot = editor.buffer().read(cx).snapshot(cx);
21931                    let comments = editor.comments_for_hunk(hunk_key, &snapshot).to_vec();
21932                    let (expanded, editors, avatar_uri, line_ranges) = editor
21933                        .diff_review_overlays
21934                        .iter()
21935                        .find(|overlay| {
21936                            Editor::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot)
21937                        })
21938                        .map(|o| {
21939                            let start_point = o.anchor_range.start.to_point(&snapshot);
21940                            let end_point = o.anchor_range.end.to_point(&snapshot);
21941                            // Get line ranges per excerpt to detect discontinuities
21942                            let buffer_ranges =
21943                                snapshot.range_to_buffer_ranges(start_point..end_point);
21944                            let ranges: Vec<(u32, u32)> = buffer_ranges
21945                                .iter()
21946                                .map(|(buffer, range, _)| {
21947                                    let start = buffer.offset_to_point(range.start.0).row;
21948                                    let end = buffer.offset_to_point(range.end.0).row;
21949                                    (start, end)
21950                                })
21951                                .collect();
21952                            (
21953                                o.comments_expanded,
21954                                o.inline_edit_editors.clone(),
21955                                o.user_avatar_uri.clone(),
21956                                if ranges.is_empty() {
21957                                    None
21958                                } else {
21959                                    Some(ranges)
21960                                },
21961                            )
21962                        })
21963                        .unwrap_or((true, HashMap::default(), None, None));
21964                    (comments, expanded, editors, avatar_uri, line_ranges)
21965                })
21966                .unwrap_or((Vec::new(), true, HashMap::default(), None, None));
21967
21968        let comment_count = comments.len();
21969        let avatar_size = px(20.);
21970        let action_icon_size = IconSize::XSmall;
21971
21972        v_flex()
21973            .w_full()
21974            .bg(colors.editor_background)
21975            .border_b_1()
21976            .border_color(colors.border)
21977            .px_2()
21978            .pb_2()
21979            .gap_2()
21980            // Line range indicator (only shown for multi-line selections or multiple excerpts)
21981            .when_some(line_ranges, |el, ranges| {
21982                let label = format_line_ranges(&ranges);
21983                if let Some(label) = label {
21984                    el.child(
21985                        h_flex()
21986                            .w_full()
21987                            .px_2()
21988                            .child(Label::new(label).size(LabelSize::Small).color(Color::Muted)),
21989                    )
21990                } else {
21991                    el
21992                }
21993            })
21994            // Top row: editable input with user's avatar
21995            .child(
21996                h_flex()
21997                    .w_full()
21998                    .items_center()
21999                    .gap_2()
22000                    .px_2()
22001                    .py_1p5()
22002                    .rounded_md()
22003                    .bg(colors.surface_background)
22004                    .child(
22005                        div()
22006                            .size(avatar_size)
22007                            .flex_shrink_0()
22008                            .rounded_full()
22009                            .overflow_hidden()
22010                            .child(if let Some(ref avatar_uri) = user_avatar_uri {
22011                                Avatar::new(avatar_uri.clone())
22012                                    .size(avatar_size)
22013                                    .into_any_element()
22014                            } else {
22015                                Icon::new(IconName::Person)
22016                                    .size(IconSize::Small)
22017                                    .color(ui::Color::Muted)
22018                                    .into_any_element()
22019                            }),
22020                    )
22021                    .child(
22022                        div()
22023                            .flex_1()
22024                            .border_1()
22025                            .border_color(colors.border)
22026                            .rounded_md()
22027                            .bg(colors.editor_background)
22028                            .px_2()
22029                            .py_1()
22030                            .child(prompt_editor.clone()),
22031                    )
22032                    .child(
22033                        h_flex()
22034                            .flex_shrink_0()
22035                            .gap_1()
22036                            .child(
22037                                IconButton::new("diff-review-close", IconName::Close)
22038                                    .icon_color(ui::Color::Muted)
22039                                    .icon_size(action_icon_size)
22040                                    .tooltip(Tooltip::text("Close"))
22041                                    .on_click(|_, window, cx| {
22042                                        window
22043                                            .dispatch_action(Box::new(crate::actions::Cancel), cx);
22044                                    }),
22045                            )
22046                            .child(
22047                                IconButton::new("diff-review-add", IconName::Return)
22048                                    .icon_color(ui::Color::Muted)
22049                                    .icon_size(action_icon_size)
22050                                    .tooltip(Tooltip::text("Add comment"))
22051                                    .on_click(|_, window, cx| {
22052                                        window.dispatch_action(
22053                                            Box::new(crate::actions::SubmitDiffReviewComment),
22054                                            cx,
22055                                        );
22056                                    }),
22057                            ),
22058                    ),
22059            )
22060            // Expandable comments section (only shown when there are comments)
22061            .when(comment_count > 0, |el| {
22062                el.child(Self::render_comments_section(
22063                    comments,
22064                    comments_expanded,
22065                    inline_editors,
22066                    user_avatar_uri,
22067                    avatar_size,
22068                    action_icon_size,
22069                    colors,
22070                ))
22071            })
22072            .into_any_element()
22073    }
22074
22075    fn render_comments_section(
22076        comments: Vec<StoredReviewComment>,
22077        expanded: bool,
22078        inline_editors: HashMap<usize, Entity<Editor>>,
22079        user_avatar_uri: Option<SharedUri>,
22080        avatar_size: Pixels,
22081        action_icon_size: IconSize,
22082        colors: &theme::ThemeColors,
22083    ) -> impl IntoElement {
22084        let comment_count = comments.len();
22085
22086        v_flex()
22087            .w_full()
22088            .gap_1()
22089            // Header with expand/collapse toggle
22090            .child(
22091                h_flex()
22092                    .id("review-comments-header")
22093                    .w_full()
22094                    .items_center()
22095                    .gap_1()
22096                    .px_2()
22097                    .py_1()
22098                    .cursor_pointer()
22099                    .rounded_md()
22100                    .hover(|style| style.bg(colors.ghost_element_hover))
22101                    .on_click(|_, window: &mut Window, cx| {
22102                        window.dispatch_action(
22103                            Box::new(crate::actions::ToggleReviewCommentsExpanded),
22104                            cx,
22105                        );
22106                    })
22107                    .child(
22108                        Icon::new(if expanded {
22109                            IconName::ChevronDown
22110                        } else {
22111                            IconName::ChevronRight
22112                        })
22113                        .size(IconSize::Small)
22114                        .color(ui::Color::Muted),
22115                    )
22116                    .child(
22117                        Label::new(format!(
22118                            "{} Comment{}",
22119                            comment_count,
22120                            if comment_count == 1 { "" } else { "s" }
22121                        ))
22122                        .size(LabelSize::Small)
22123                        .color(Color::Muted),
22124                    ),
22125            )
22126            // Comments list (when expanded)
22127            .when(expanded, |el| {
22128                el.children(comments.into_iter().map(|comment| {
22129                    let inline_editor = inline_editors.get(&comment.id).cloned();
22130                    Self::render_comment_row(
22131                        comment,
22132                        inline_editor,
22133                        user_avatar_uri.clone(),
22134                        avatar_size,
22135                        action_icon_size,
22136                        colors,
22137                    )
22138                }))
22139            })
22140    }
22141
22142    fn render_comment_row(
22143        comment: StoredReviewComment,
22144        inline_editor: Option<Entity<Editor>>,
22145        user_avatar_uri: Option<SharedUri>,
22146        avatar_size: Pixels,
22147        action_icon_size: IconSize,
22148        colors: &theme::ThemeColors,
22149    ) -> impl IntoElement {
22150        let comment_id = comment.id;
22151        let is_editing = inline_editor.is_some();
22152
22153        h_flex()
22154            .w_full()
22155            .items_center()
22156            .gap_2()
22157            .px_2()
22158            .py_1p5()
22159            .rounded_md()
22160            .bg(colors.surface_background)
22161            .child(
22162                div()
22163                    .size(avatar_size)
22164                    .flex_shrink_0()
22165                    .rounded_full()
22166                    .overflow_hidden()
22167                    .child(if let Some(ref avatar_uri) = user_avatar_uri {
22168                        Avatar::new(avatar_uri.clone())
22169                            .size(avatar_size)
22170                            .into_any_element()
22171                    } else {
22172                        Icon::new(IconName::Person)
22173                            .size(IconSize::Small)
22174                            .color(ui::Color::Muted)
22175                            .into_any_element()
22176                    }),
22177            )
22178            .child(if let Some(editor) = inline_editor {
22179                // Inline edit mode: show an editable text field
22180                div()
22181                    .flex_1()
22182                    .border_1()
22183                    .border_color(colors.border)
22184                    .rounded_md()
22185                    .bg(colors.editor_background)
22186                    .px_2()
22187                    .py_1()
22188                    .child(editor)
22189                    .into_any_element()
22190            } else {
22191                // Display mode: show the comment text
22192                div()
22193                    .flex_1()
22194                    .text_sm()
22195                    .text_color(colors.text)
22196                    .child(comment.comment)
22197                    .into_any_element()
22198            })
22199            .child(if is_editing {
22200                // Editing mode: show close and confirm buttons
22201                h_flex()
22202                    .gap_1()
22203                    .child(
22204                        IconButton::new(
22205                            format!("diff-review-cancel-edit-{comment_id}"),
22206                            IconName::Close,
22207                        )
22208                        .icon_color(ui::Color::Muted)
22209                        .icon_size(action_icon_size)
22210                        .tooltip(Tooltip::text("Cancel"))
22211                        .on_click(move |_, window, cx| {
22212                            window.dispatch_action(
22213                                Box::new(crate::actions::CancelEditReviewComment {
22214                                    id: comment_id,
22215                                }),
22216                                cx,
22217                            );
22218                        }),
22219                    )
22220                    .child(
22221                        IconButton::new(
22222                            format!("diff-review-confirm-edit-{comment_id}"),
22223                            IconName::Return,
22224                        )
22225                        .icon_color(ui::Color::Muted)
22226                        .icon_size(action_icon_size)
22227                        .tooltip(Tooltip::text("Confirm"))
22228                        .on_click(move |_, window, cx| {
22229                            window.dispatch_action(
22230                                Box::new(crate::actions::ConfirmEditReviewComment {
22231                                    id: comment_id,
22232                                }),
22233                                cx,
22234                            );
22235                        }),
22236                    )
22237                    .into_any_element()
22238            } else {
22239                // Display mode: no action buttons for now (edit/delete not yet implemented)
22240                gpui::Empty.into_any_element()
22241            })
22242    }
22243
22244    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
22245        if self.display_map.read(cx).masked != masked {
22246            self.display_map.update(cx, |map, _| map.masked = masked);
22247        }
22248        cx.notify()
22249    }
22250
22251    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
22252        self.show_wrap_guides = Some(show_wrap_guides);
22253        cx.notify();
22254    }
22255
22256    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
22257        self.show_indent_guides = Some(show_indent_guides);
22258        cx.notify();
22259    }
22260
22261    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
22262        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
22263            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
22264                && let Some(dir) = file.abs_path(cx).parent()
22265            {
22266                return Some(dir.to_owned());
22267            }
22268        }
22269
22270        None
22271    }
22272
22273    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
22274        self.active_excerpt(cx)?
22275            .1
22276            .read(cx)
22277            .file()
22278            .and_then(|f| f.as_local())
22279    }
22280
22281    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
22282        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22283            let buffer = buffer.read(cx);
22284            if let Some(project_path) = buffer.project_path(cx) {
22285                let project = self.project()?.read(cx);
22286                project.absolute_path(&project_path, cx)
22287            } else {
22288                buffer
22289                    .file()
22290                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
22291            }
22292        })
22293    }
22294
22295    pub fn reveal_in_finder(
22296        &mut self,
22297        _: &RevealInFileManager,
22298        _window: &mut Window,
22299        cx: &mut Context<Self>,
22300    ) {
22301        if let Some(path) = self.target_file_abs_path(cx) {
22302            if let Some(project) = self.project() {
22303                project.update(cx, |project, cx| project.reveal_path(&path, cx));
22304            } else {
22305                cx.reveal_path(&path);
22306            }
22307        }
22308    }
22309
22310    pub fn copy_path(
22311        &mut self,
22312        _: &zed_actions::workspace::CopyPath,
22313        _window: &mut Window,
22314        cx: &mut Context<Self>,
22315    ) {
22316        if let Some(path) = self.target_file_abs_path(cx)
22317            && let Some(path) = path.to_str()
22318        {
22319            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
22320        } else {
22321            cx.propagate();
22322        }
22323    }
22324
22325    pub fn copy_relative_path(
22326        &mut self,
22327        _: &zed_actions::workspace::CopyRelativePath,
22328        _window: &mut Window,
22329        cx: &mut Context<Self>,
22330    ) {
22331        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22332            let project = self.project()?.read(cx);
22333            let path = buffer.read(cx).file()?.path();
22334            let path = path.display(project.path_style(cx));
22335            Some(path)
22336        }) {
22337            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
22338        } else {
22339            cx.propagate();
22340        }
22341    }
22342
22343    /// Returns the project path for the editor's buffer, if any buffer is
22344    /// opened in the editor.
22345    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
22346        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
22347            buffer.read(cx).project_path(cx)
22348        } else {
22349            None
22350        }
22351    }
22352
22353    // Returns true if the editor handled a go-to-line request
22354    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
22355        maybe!({
22356            let breakpoint_store = self.breakpoint_store.as_ref()?;
22357
22358            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
22359            else {
22360                self.clear_row_highlights::<ActiveDebugLine>();
22361                return None;
22362            };
22363
22364            let position = active_stack_frame.position;
22365            let buffer_id = position.buffer_id?;
22366            let snapshot = self
22367                .project
22368                .as_ref()?
22369                .read(cx)
22370                .buffer_for_id(buffer_id, cx)?
22371                .read(cx)
22372                .snapshot();
22373
22374            let mut handled = false;
22375            for (id, ExcerptRange { context, .. }) in
22376                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
22377            {
22378                if context.start.cmp(&position, &snapshot).is_ge()
22379                    || context.end.cmp(&position, &snapshot).is_lt()
22380                {
22381                    continue;
22382                }
22383                let snapshot = self.buffer.read(cx).snapshot(cx);
22384                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
22385
22386                handled = true;
22387                self.clear_row_highlights::<ActiveDebugLine>();
22388
22389                self.go_to_line::<ActiveDebugLine>(
22390                    multibuffer_anchor,
22391                    Some(cx.theme().colors().editor_debugger_active_line_background),
22392                    window,
22393                    cx,
22394                );
22395
22396                cx.notify();
22397            }
22398
22399            handled.then_some(())
22400        })
22401        .is_some()
22402    }
22403
22404    pub fn copy_file_name_without_extension(
22405        &mut self,
22406        _: &CopyFileNameWithoutExtension,
22407        _: &mut Window,
22408        cx: &mut Context<Self>,
22409    ) {
22410        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22411            let file = buffer.read(cx).file()?;
22412            file.path().file_stem()
22413        }) {
22414            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
22415        }
22416    }
22417
22418    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
22419        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22420            let file = buffer.read(cx).file()?;
22421            Some(file.file_name(cx))
22422        }) {
22423            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
22424        }
22425    }
22426
22427    pub fn toggle_git_blame(
22428        &mut self,
22429        _: &::git::Blame,
22430        window: &mut Window,
22431        cx: &mut Context<Self>,
22432    ) {
22433        self.show_git_blame_gutter = !self.show_git_blame_gutter;
22434
22435        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
22436            self.start_git_blame(true, window, cx);
22437        }
22438
22439        cx.notify();
22440    }
22441
22442    pub fn toggle_git_blame_inline(
22443        &mut self,
22444        _: &ToggleGitBlameInline,
22445        window: &mut Window,
22446        cx: &mut Context<Self>,
22447    ) {
22448        self.toggle_git_blame_inline_internal(true, window, cx);
22449        cx.notify();
22450    }
22451
22452    pub fn open_git_blame_commit(
22453        &mut self,
22454        _: &OpenGitBlameCommit,
22455        window: &mut Window,
22456        cx: &mut Context<Self>,
22457    ) {
22458        self.open_git_blame_commit_internal(window, cx);
22459    }
22460
22461    fn open_git_blame_commit_internal(
22462        &mut self,
22463        window: &mut Window,
22464        cx: &mut Context<Self>,
22465    ) -> Option<()> {
22466        let blame = self.blame.as_ref()?;
22467        let snapshot = self.snapshot(window, cx);
22468        let cursor = self
22469            .selections
22470            .newest::<Point>(&snapshot.display_snapshot)
22471            .head();
22472        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
22473        let (_, blame_entry) = blame
22474            .update(cx, |blame, cx| {
22475                blame
22476                    .blame_for_rows(
22477                        &[RowInfo {
22478                            buffer_id: Some(buffer.remote_id()),
22479                            buffer_row: Some(point.row),
22480                            ..Default::default()
22481                        }],
22482                        cx,
22483                    )
22484                    .next()
22485            })
22486            .flatten()?;
22487        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22488        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
22489        let workspace = self.workspace()?.downgrade();
22490        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
22491        None
22492    }
22493
22494    pub fn git_blame_inline_enabled(&self) -> bool {
22495        self.git_blame_inline_enabled
22496    }
22497
22498    pub fn toggle_selection_menu(
22499        &mut self,
22500        _: &ToggleSelectionMenu,
22501        _: &mut Window,
22502        cx: &mut Context<Self>,
22503    ) {
22504        self.show_selection_menu = self
22505            .show_selection_menu
22506            .map(|show_selections_menu| !show_selections_menu)
22507            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
22508
22509        cx.notify();
22510    }
22511
22512    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
22513        self.show_selection_menu
22514            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
22515    }
22516
22517    fn start_git_blame(
22518        &mut self,
22519        user_triggered: bool,
22520        window: &mut Window,
22521        cx: &mut Context<Self>,
22522    ) {
22523        if let Some(project) = self.project() {
22524            if let Some(buffer) = self.buffer().read(cx).as_singleton()
22525                && buffer.read(cx).file().is_none()
22526            {
22527                return;
22528            }
22529
22530            let focused = self.focus_handle(cx).contains_focused(window, cx);
22531
22532            let project = project.clone();
22533            let blame = cx
22534                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
22535            self.blame_subscription =
22536                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
22537            self.blame = Some(blame);
22538        }
22539    }
22540
22541    fn toggle_git_blame_inline_internal(
22542        &mut self,
22543        user_triggered: bool,
22544        window: &mut Window,
22545        cx: &mut Context<Self>,
22546    ) {
22547        if self.git_blame_inline_enabled {
22548            self.git_blame_inline_enabled = false;
22549            self.show_git_blame_inline = false;
22550            self.show_git_blame_inline_delay_task.take();
22551        } else {
22552            self.git_blame_inline_enabled = true;
22553            self.start_git_blame_inline(user_triggered, window, cx);
22554        }
22555
22556        cx.notify();
22557    }
22558
22559    fn start_git_blame_inline(
22560        &mut self,
22561        user_triggered: bool,
22562        window: &mut Window,
22563        cx: &mut Context<Self>,
22564    ) {
22565        self.start_git_blame(user_triggered, window, cx);
22566
22567        if ProjectSettings::get_global(cx)
22568            .git
22569            .inline_blame_delay()
22570            .is_some()
22571        {
22572            self.start_inline_blame_timer(window, cx);
22573        } else {
22574            self.show_git_blame_inline = true
22575        }
22576    }
22577
22578    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
22579        self.blame.as_ref()
22580    }
22581
22582    pub fn show_git_blame_gutter(&self) -> bool {
22583        self.show_git_blame_gutter
22584    }
22585
22586    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
22587        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
22588    }
22589
22590    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
22591        self.show_git_blame_inline
22592            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
22593            && !self.newest_selection_head_on_empty_line(cx)
22594            && self.has_blame_entries(cx)
22595    }
22596
22597    fn has_blame_entries(&self, cx: &App) -> bool {
22598        self.blame()
22599            .is_some_and(|blame| blame.read(cx).has_generated_entries())
22600    }
22601
22602    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
22603        let cursor_anchor = self.selections.newest_anchor().head();
22604
22605        let snapshot = self.buffer.read(cx).snapshot(cx);
22606        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
22607
22608        snapshot.line_len(buffer_row) == 0
22609    }
22610
22611    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
22612        let buffer_and_selection = maybe!({
22613            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
22614            let selection_range = selection.range();
22615
22616            let multi_buffer = self.buffer().read(cx);
22617            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
22618            let buffer_ranges = multi_buffer_snapshot
22619                .range_to_buffer_ranges(selection_range.start..=selection_range.end);
22620
22621            let (buffer, range, _) = if selection.reversed {
22622                buffer_ranges.first()
22623            } else {
22624                buffer_ranges.last()
22625            }?;
22626
22627            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
22628            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
22629
22630            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
22631                let selection = start_row_in_buffer..end_row_in_buffer;
22632
22633                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
22634            };
22635
22636            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
22637            let (mut translated, _, _) = buffer_diff_snapshot.points_to_base_text_points(
22638                [
22639                    Point::new(start_row_in_buffer, 0),
22640                    Point::new(end_row_in_buffer, 0),
22641                ],
22642                buffer,
22643            );
22644            let start_row = translated.next().unwrap().start.row;
22645            let end_row = translated.next().unwrap().end.row;
22646
22647            Some((
22648                multi_buffer.buffer(buffer.remote_id()).unwrap(),
22649                start_row..end_row,
22650            ))
22651        });
22652
22653        let Some((buffer, selection)) = buffer_and_selection else {
22654            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
22655        };
22656
22657        let Some(project) = self.project() else {
22658            return Task::ready(Err(anyhow!("editor does not have project")));
22659        };
22660
22661        project.update(cx, |project, cx| {
22662            project.get_permalink_to_line(&buffer, selection, cx)
22663        })
22664    }
22665
22666    pub fn copy_permalink_to_line(
22667        &mut self,
22668        _: &CopyPermalinkToLine,
22669        window: &mut Window,
22670        cx: &mut Context<Self>,
22671    ) {
22672        let permalink_task = self.get_permalink_to_line(cx);
22673        let workspace = self.workspace();
22674
22675        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
22676            Ok(permalink) => {
22677                cx.update(|_, cx| {
22678                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
22679                })
22680                .ok();
22681            }
22682            Err(err) => {
22683                let message = format!("Failed to copy permalink: {err}");
22684
22685                anyhow::Result::<()>::Err(err).log_err();
22686
22687                if let Some(workspace) = workspace {
22688                    workspace
22689                        .update_in(cx, |workspace, _, cx| {
22690                            struct CopyPermalinkToLine;
22691
22692                            workspace.show_toast(
22693                                Toast::new(
22694                                    NotificationId::unique::<CopyPermalinkToLine>(),
22695                                    message,
22696                                ),
22697                                cx,
22698                            )
22699                        })
22700                        .ok();
22701                }
22702            }
22703        })
22704        .detach();
22705    }
22706
22707    pub fn copy_file_location(
22708        &mut self,
22709        _: &CopyFileLocation,
22710        _: &mut Window,
22711        cx: &mut Context<Self>,
22712    ) {
22713        let selection = self
22714            .selections
22715            .newest::<Point>(&self.display_snapshot(cx))
22716            .start
22717            .row
22718            + 1;
22719        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22720            let project = self.project()?.read(cx);
22721            let file = buffer.read(cx).file()?;
22722            let path = file.path().display(project.path_style(cx));
22723
22724            Some(format!("{path}:{selection}"))
22725        }) {
22726            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
22727        }
22728    }
22729
22730    pub fn open_permalink_to_line(
22731        &mut self,
22732        _: &OpenPermalinkToLine,
22733        window: &mut Window,
22734        cx: &mut Context<Self>,
22735    ) {
22736        let permalink_task = self.get_permalink_to_line(cx);
22737        let workspace = self.workspace();
22738
22739        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
22740            Ok(permalink) => {
22741                cx.update(|_, cx| {
22742                    cx.open_url(permalink.as_ref());
22743                })
22744                .ok();
22745            }
22746            Err(err) => {
22747                let message = format!("Failed to open permalink: {err}");
22748
22749                anyhow::Result::<()>::Err(err).log_err();
22750
22751                if let Some(workspace) = workspace {
22752                    workspace.update(cx, |workspace, cx| {
22753                        struct OpenPermalinkToLine;
22754
22755                        workspace.show_toast(
22756                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
22757                            cx,
22758                        )
22759                    });
22760                }
22761            }
22762        })
22763        .detach();
22764    }
22765
22766    pub fn insert_uuid_v4(
22767        &mut self,
22768        _: &InsertUuidV4,
22769        window: &mut Window,
22770        cx: &mut Context<Self>,
22771    ) {
22772        self.insert_uuid(UuidVersion::V4, window, cx);
22773    }
22774
22775    pub fn insert_uuid_v7(
22776        &mut self,
22777        _: &InsertUuidV7,
22778        window: &mut Window,
22779        cx: &mut Context<Self>,
22780    ) {
22781        self.insert_uuid(UuidVersion::V7, window, cx);
22782    }
22783
22784    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
22785        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
22786        self.transact(window, cx, |this, window, cx| {
22787            let edits = this
22788                .selections
22789                .all::<Point>(&this.display_snapshot(cx))
22790                .into_iter()
22791                .map(|selection| {
22792                    let uuid = match version {
22793                        UuidVersion::V4 => uuid::Uuid::new_v4(),
22794                        UuidVersion::V7 => uuid::Uuid::now_v7(),
22795                    };
22796
22797                    (selection.range(), uuid.to_string())
22798                });
22799            this.edit(edits, cx);
22800            this.refresh_edit_prediction(true, false, window, cx);
22801        });
22802    }
22803
22804    pub fn open_selections_in_multibuffer(
22805        &mut self,
22806        _: &OpenSelectionsInMultibuffer,
22807        window: &mut Window,
22808        cx: &mut Context<Self>,
22809    ) {
22810        let multibuffer = self.buffer.read(cx);
22811
22812        let Some(buffer) = multibuffer.as_singleton() else {
22813            return;
22814        };
22815
22816        let Some(workspace) = self.workspace() else {
22817            return;
22818        };
22819
22820        let title = multibuffer.title(cx).to_string();
22821
22822        let locations = self
22823            .selections
22824            .all_anchors(&self.display_snapshot(cx))
22825            .iter()
22826            .map(|selection| {
22827                (
22828                    buffer.clone(),
22829                    (selection.start.text_anchor..selection.end.text_anchor)
22830                        .to_point(buffer.read(cx)),
22831                )
22832            })
22833            .into_group_map();
22834
22835        cx.spawn_in(window, async move |_, cx| {
22836            workspace.update_in(cx, |workspace, window, cx| {
22837                Self::open_locations_in_multibuffer(
22838                    workspace,
22839                    locations,
22840                    format!("Selections for '{title}'"),
22841                    false,
22842                    false,
22843                    MultibufferSelectionMode::All,
22844                    window,
22845                    cx,
22846                );
22847            })
22848        })
22849        .detach();
22850    }
22851
22852    /// Adds a row highlight for the given range. If a row has multiple highlights, the
22853    /// last highlight added will be used.
22854    ///
22855    /// If the range ends at the beginning of a line, then that line will not be highlighted.
22856    pub fn highlight_rows<T: 'static>(
22857        &mut self,
22858        range: Range<Anchor>,
22859        color: Hsla,
22860        options: RowHighlightOptions,
22861        cx: &mut Context<Self>,
22862    ) {
22863        let snapshot = self.buffer().read(cx).snapshot(cx);
22864        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
22865        let ix = row_highlights.binary_search_by(|highlight| {
22866            Ordering::Equal
22867                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
22868                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
22869        });
22870
22871        if let Err(mut ix) = ix {
22872            let index = post_inc(&mut self.highlight_order);
22873
22874            // If this range intersects with the preceding highlight, then merge it with
22875            // the preceding highlight. Otherwise insert a new highlight.
22876            let mut merged = false;
22877            if ix > 0 {
22878                let prev_highlight = &mut row_highlights[ix - 1];
22879                if prev_highlight
22880                    .range
22881                    .end
22882                    .cmp(&range.start, &snapshot)
22883                    .is_ge()
22884                {
22885                    ix -= 1;
22886                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
22887                        prev_highlight.range.end = range.end;
22888                    }
22889                    merged = true;
22890                    prev_highlight.index = index;
22891                    prev_highlight.color = color;
22892                    prev_highlight.options = options;
22893                }
22894            }
22895
22896            if !merged {
22897                row_highlights.insert(
22898                    ix,
22899                    RowHighlight {
22900                        range,
22901                        index,
22902                        color,
22903                        options,
22904                        type_id: TypeId::of::<T>(),
22905                    },
22906                );
22907            }
22908
22909            // If any of the following highlights intersect with this one, merge them.
22910            while let Some(next_highlight) = row_highlights.get(ix + 1) {
22911                let highlight = &row_highlights[ix];
22912                if next_highlight
22913                    .range
22914                    .start
22915                    .cmp(&highlight.range.end, &snapshot)
22916                    .is_le()
22917                {
22918                    if next_highlight
22919                        .range
22920                        .end
22921                        .cmp(&highlight.range.end, &snapshot)
22922                        .is_gt()
22923                    {
22924                        row_highlights[ix].range.end = next_highlight.range.end;
22925                    }
22926                    row_highlights.remove(ix + 1);
22927                } else {
22928                    break;
22929                }
22930            }
22931        }
22932    }
22933
22934    /// Remove any highlighted row ranges of the given type that intersect the
22935    /// given ranges.
22936    pub fn remove_highlighted_rows<T: 'static>(
22937        &mut self,
22938        ranges_to_remove: Vec<Range<Anchor>>,
22939        cx: &mut Context<Self>,
22940    ) {
22941        let snapshot = self.buffer().read(cx).snapshot(cx);
22942        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
22943        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
22944        row_highlights.retain(|highlight| {
22945            while let Some(range_to_remove) = ranges_to_remove.peek() {
22946                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
22947                    Ordering::Less | Ordering::Equal => {
22948                        ranges_to_remove.next();
22949                    }
22950                    Ordering::Greater => {
22951                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
22952                            Ordering::Less | Ordering::Equal => {
22953                                return false;
22954                            }
22955                            Ordering::Greater => break,
22956                        }
22957                    }
22958                }
22959            }
22960
22961            true
22962        })
22963    }
22964
22965    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
22966    pub fn clear_row_highlights<T: 'static>(&mut self) {
22967        self.highlighted_rows.remove(&TypeId::of::<T>());
22968    }
22969
22970    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
22971    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
22972        self.highlighted_rows
22973            .get(&TypeId::of::<T>())
22974            .map_or(&[] as &[_], |vec| vec.as_slice())
22975            .iter()
22976            .map(|highlight| (highlight.range.clone(), highlight.color))
22977    }
22978
22979    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
22980    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
22981    /// Allows to ignore certain kinds of highlights.
22982    pub fn highlighted_display_rows(
22983        &self,
22984        window: &mut Window,
22985        cx: &mut App,
22986    ) -> BTreeMap<DisplayRow, LineHighlight> {
22987        let snapshot = self.snapshot(window, cx);
22988        let mut used_highlight_orders = HashMap::default();
22989        self.highlighted_rows
22990            .iter()
22991            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
22992            .fold(
22993                BTreeMap::<DisplayRow, LineHighlight>::new(),
22994                |mut unique_rows, highlight| {
22995                    let start = highlight.range.start.to_display_point(&snapshot);
22996                    let end = highlight.range.end.to_display_point(&snapshot);
22997                    let start_row = start.row().0;
22998                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
22999                    {
23000                        end.row().0.saturating_sub(1)
23001                    } else {
23002                        end.row().0
23003                    };
23004                    for row in start_row..=end_row {
23005                        let used_index =
23006                            used_highlight_orders.entry(row).or_insert(highlight.index);
23007                        if highlight.index >= *used_index {
23008                            *used_index = highlight.index;
23009                            unique_rows.insert(
23010                                DisplayRow(row),
23011                                LineHighlight {
23012                                    include_gutter: highlight.options.include_gutter,
23013                                    border: None,
23014                                    background: highlight.color.into(),
23015                                    type_id: Some(highlight.type_id),
23016                                },
23017                            );
23018                        }
23019                    }
23020                    unique_rows
23021                },
23022            )
23023    }
23024
23025    pub fn highlighted_display_row_for_autoscroll(
23026        &self,
23027        snapshot: &DisplaySnapshot,
23028    ) -> Option<DisplayRow> {
23029        self.highlighted_rows
23030            .values()
23031            .flat_map(|highlighted_rows| highlighted_rows.iter())
23032            .filter_map(|highlight| {
23033                if highlight.options.autoscroll {
23034                    Some(highlight.range.start.to_display_point(snapshot).row())
23035                } else {
23036                    None
23037                }
23038            })
23039            .min()
23040    }
23041
23042    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
23043        self.highlight_background::<SearchWithinRange>(
23044            ranges,
23045            |_, colors| colors.colors().editor_document_highlight_read_background,
23046            cx,
23047        )
23048    }
23049
23050    pub fn set_breadcrumb_header(&mut self, new_header: String) {
23051        self.breadcrumb_header = Some(new_header);
23052    }
23053
23054    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
23055        self.clear_background_highlights::<SearchWithinRange>(cx);
23056    }
23057
23058    pub fn highlight_background<T: 'static>(
23059        &mut self,
23060        ranges: &[Range<Anchor>],
23061        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
23062        cx: &mut Context<Self>,
23063    ) {
23064        self.background_highlights.insert(
23065            HighlightKey::Type(TypeId::of::<T>()),
23066            (Arc::new(color_fetcher), Arc::from(ranges)),
23067        );
23068        self.scrollbar_marker_state.dirty = true;
23069        cx.notify();
23070    }
23071
23072    pub fn highlight_background_key<T: 'static>(
23073        &mut self,
23074        key: usize,
23075        ranges: &[Range<Anchor>],
23076        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
23077        cx: &mut Context<Self>,
23078    ) {
23079        self.background_highlights.insert(
23080            HighlightKey::TypePlus(TypeId::of::<T>(), key),
23081            (Arc::new(color_fetcher), Arc::from(ranges)),
23082        );
23083        self.scrollbar_marker_state.dirty = true;
23084        cx.notify();
23085    }
23086
23087    pub fn clear_background_highlights<T: 'static>(
23088        &mut self,
23089        cx: &mut Context<Self>,
23090    ) -> Option<BackgroundHighlight> {
23091        let text_highlights = self
23092            .background_highlights
23093            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
23094        if !text_highlights.1.is_empty() {
23095            self.scrollbar_marker_state.dirty = true;
23096            cx.notify();
23097        }
23098        Some(text_highlights)
23099    }
23100
23101    pub fn clear_background_highlights_key<T: 'static>(
23102        &mut self,
23103        key: usize,
23104        cx: &mut Context<Self>,
23105    ) -> Option<BackgroundHighlight> {
23106        let text_highlights = self
23107            .background_highlights
23108            .remove(&HighlightKey::TypePlus(TypeId::of::<T>(), key))?;
23109        if !text_highlights.1.is_empty() {
23110            self.scrollbar_marker_state.dirty = true;
23111            cx.notify();
23112        }
23113        Some(text_highlights)
23114    }
23115
23116    pub fn highlight_gutter<T: 'static>(
23117        &mut self,
23118        ranges: impl Into<Vec<Range<Anchor>>>,
23119        color_fetcher: fn(&App) -> Hsla,
23120        cx: &mut Context<Self>,
23121    ) {
23122        self.gutter_highlights
23123            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
23124        cx.notify();
23125    }
23126
23127    pub fn clear_gutter_highlights<T: 'static>(
23128        &mut self,
23129        cx: &mut Context<Self>,
23130    ) -> Option<GutterHighlight> {
23131        cx.notify();
23132        self.gutter_highlights.remove(&TypeId::of::<T>())
23133    }
23134
23135    pub fn insert_gutter_highlight<T: 'static>(
23136        &mut self,
23137        range: Range<Anchor>,
23138        color_fetcher: fn(&App) -> Hsla,
23139        cx: &mut Context<Self>,
23140    ) {
23141        let snapshot = self.buffer().read(cx).snapshot(cx);
23142        let mut highlights = self
23143            .gutter_highlights
23144            .remove(&TypeId::of::<T>())
23145            .map(|(_, highlights)| highlights)
23146            .unwrap_or_default();
23147        let ix = highlights.binary_search_by(|highlight| {
23148            Ordering::Equal
23149                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
23150                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
23151        });
23152        if let Err(ix) = ix {
23153            highlights.insert(ix, range);
23154        }
23155        self.gutter_highlights
23156            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
23157    }
23158
23159    pub fn remove_gutter_highlights<T: 'static>(
23160        &mut self,
23161        ranges_to_remove: Vec<Range<Anchor>>,
23162        cx: &mut Context<Self>,
23163    ) {
23164        let snapshot = self.buffer().read(cx).snapshot(cx);
23165        let Some((color_fetcher, mut gutter_highlights)) =
23166            self.gutter_highlights.remove(&TypeId::of::<T>())
23167        else {
23168            return;
23169        };
23170        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23171        gutter_highlights.retain(|highlight| {
23172            while let Some(range_to_remove) = ranges_to_remove.peek() {
23173                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
23174                    Ordering::Less | Ordering::Equal => {
23175                        ranges_to_remove.next();
23176                    }
23177                    Ordering::Greater => {
23178                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
23179                            Ordering::Less | Ordering::Equal => {
23180                                return false;
23181                            }
23182                            Ordering::Greater => break,
23183                        }
23184                    }
23185                }
23186            }
23187
23188            true
23189        });
23190        self.gutter_highlights
23191            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
23192    }
23193
23194    #[cfg(feature = "test-support")]
23195    pub fn all_text_highlights(
23196        &self,
23197        window: &mut Window,
23198        cx: &mut Context<Self>,
23199    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
23200        let snapshot = self.snapshot(window, cx);
23201        self.display_map.update(cx, |display_map, _| {
23202            display_map
23203                .all_text_highlights()
23204                .map(|highlight| {
23205                    let (style, ranges) = highlight.as_ref();
23206                    (
23207                        *style,
23208                        ranges
23209                            .iter()
23210                            .map(|range| range.clone().to_display_points(&snapshot))
23211                            .collect(),
23212                    )
23213                })
23214                .collect()
23215        })
23216    }
23217
23218    #[cfg(feature = "test-support")]
23219    pub fn all_text_background_highlights(
23220        &self,
23221        window: &mut Window,
23222        cx: &mut Context<Self>,
23223    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23224        let snapshot = self.snapshot(window, cx);
23225        let buffer = &snapshot.buffer_snapshot();
23226        let start = buffer.anchor_before(MultiBufferOffset(0));
23227        let end = buffer.anchor_after(buffer.len());
23228        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
23229    }
23230
23231    #[cfg(any(test, feature = "test-support"))]
23232    pub fn sorted_background_highlights_in_range(
23233        &self,
23234        search_range: Range<Anchor>,
23235        display_snapshot: &DisplaySnapshot,
23236        theme: &Theme,
23237    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23238        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
23239        res.sort_by(|a, b| {
23240            a.0.start
23241                .cmp(&b.0.start)
23242                .then_with(|| a.0.end.cmp(&b.0.end))
23243                .then_with(|| a.1.cmp(&b.1))
23244        });
23245        res
23246    }
23247
23248    #[cfg(feature = "test-support")]
23249    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
23250        let snapshot = self.buffer().read(cx).snapshot(cx);
23251
23252        let highlights = self
23253            .background_highlights
23254            .get(&HighlightKey::Type(TypeId::of::<
23255                items::BufferSearchHighlights,
23256            >()));
23257
23258        if let Some((_color, ranges)) = highlights {
23259            ranges
23260                .iter()
23261                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
23262                .collect_vec()
23263        } else {
23264            vec![]
23265        }
23266    }
23267
23268    fn document_highlights_for_position<'a>(
23269        &'a self,
23270        position: Anchor,
23271        buffer: &'a MultiBufferSnapshot,
23272    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
23273        let read_highlights = self
23274            .background_highlights
23275            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
23276            .map(|h| &h.1);
23277        let write_highlights = self
23278            .background_highlights
23279            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
23280            .map(|h| &h.1);
23281        let left_position = position.bias_left(buffer);
23282        let right_position = position.bias_right(buffer);
23283        read_highlights
23284            .into_iter()
23285            .chain(write_highlights)
23286            .flat_map(move |ranges| {
23287                let start_ix = match ranges.binary_search_by(|probe| {
23288                    let cmp = probe.end.cmp(&left_position, buffer);
23289                    if cmp.is_ge() {
23290                        Ordering::Greater
23291                    } else {
23292                        Ordering::Less
23293                    }
23294                }) {
23295                    Ok(i) | Err(i) => i,
23296                };
23297
23298                ranges[start_ix..]
23299                    .iter()
23300                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
23301            })
23302    }
23303
23304    pub fn has_background_highlights<T: 'static>(&self) -> bool {
23305        self.background_highlights
23306            .get(&HighlightKey::Type(TypeId::of::<T>()))
23307            .is_some_and(|(_, highlights)| !highlights.is_empty())
23308    }
23309
23310    /// Returns all background highlights for a given range.
23311    ///
23312    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
23313    pub fn background_highlights_in_range(
23314        &self,
23315        search_range: Range<Anchor>,
23316        display_snapshot: &DisplaySnapshot,
23317        theme: &Theme,
23318    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23319        let mut results = Vec::new();
23320        for (color_fetcher, ranges) in self.background_highlights.values() {
23321            let start_ix = match ranges.binary_search_by(|probe| {
23322                let cmp = probe
23323                    .end
23324                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23325                if cmp.is_gt() {
23326                    Ordering::Greater
23327                } else {
23328                    Ordering::Less
23329                }
23330            }) {
23331                Ok(i) | Err(i) => i,
23332            };
23333            for (index, range) in ranges[start_ix..].iter().enumerate() {
23334                if range
23335                    .start
23336                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23337                    .is_ge()
23338                {
23339                    break;
23340                }
23341
23342                let color = color_fetcher(&(start_ix + index), theme);
23343                let start = range.start.to_display_point(display_snapshot);
23344                let end = range.end.to_display_point(display_snapshot);
23345                results.push((start..end, color))
23346            }
23347        }
23348        results
23349    }
23350
23351    pub fn gutter_highlights_in_range(
23352        &self,
23353        search_range: Range<Anchor>,
23354        display_snapshot: &DisplaySnapshot,
23355        cx: &App,
23356    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23357        let mut results = Vec::new();
23358        for (color_fetcher, ranges) in self.gutter_highlights.values() {
23359            let color = color_fetcher(cx);
23360            let start_ix = match ranges.binary_search_by(|probe| {
23361                let cmp = probe
23362                    .end
23363                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23364                if cmp.is_gt() {
23365                    Ordering::Greater
23366                } else {
23367                    Ordering::Less
23368                }
23369            }) {
23370                Ok(i) | Err(i) => i,
23371            };
23372            for range in &ranges[start_ix..] {
23373                if range
23374                    .start
23375                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23376                    .is_ge()
23377                {
23378                    break;
23379                }
23380
23381                let start = range.start.to_display_point(display_snapshot);
23382                let end = range.end.to_display_point(display_snapshot);
23383                results.push((start..end, color))
23384            }
23385        }
23386        results
23387    }
23388
23389    /// Get the text ranges corresponding to the redaction query
23390    pub fn redacted_ranges(
23391        &self,
23392        search_range: Range<Anchor>,
23393        display_snapshot: &DisplaySnapshot,
23394        cx: &App,
23395    ) -> Vec<Range<DisplayPoint>> {
23396        display_snapshot
23397            .buffer_snapshot()
23398            .redacted_ranges(search_range, |file| {
23399                if let Some(file) = file {
23400                    file.is_private()
23401                        && EditorSettings::get(
23402                            Some(SettingsLocation {
23403                                worktree_id: file.worktree_id(cx),
23404                                path: file.path().as_ref(),
23405                            }),
23406                            cx,
23407                        )
23408                        .redact_private_values
23409                } else {
23410                    false
23411                }
23412            })
23413            .map(|range| {
23414                range.start.to_display_point(display_snapshot)
23415                    ..range.end.to_display_point(display_snapshot)
23416            })
23417            .collect()
23418    }
23419
23420    pub fn highlight_text_key<T: 'static>(
23421        &mut self,
23422        key: usize,
23423        ranges: Vec<Range<Anchor>>,
23424        style: HighlightStyle,
23425        merge: bool,
23426        cx: &mut Context<Self>,
23427    ) {
23428        self.display_map.update(cx, |map, cx| {
23429            map.highlight_text(
23430                HighlightKey::TypePlus(TypeId::of::<T>(), key),
23431                ranges,
23432                style,
23433                merge,
23434                cx,
23435            );
23436        });
23437        cx.notify();
23438    }
23439
23440    pub fn highlight_text<T: 'static>(
23441        &mut self,
23442        ranges: Vec<Range<Anchor>>,
23443        style: HighlightStyle,
23444        cx: &mut Context<Self>,
23445    ) {
23446        self.display_map.update(cx, |map, cx| {
23447            map.highlight_text(
23448                HighlightKey::Type(TypeId::of::<T>()),
23449                ranges,
23450                style,
23451                false,
23452                cx,
23453            )
23454        });
23455        cx.notify();
23456    }
23457
23458    pub fn text_highlights<'a, T: 'static>(
23459        &'a self,
23460        cx: &'a App,
23461    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
23462        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
23463    }
23464
23465    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
23466        let cleared = self
23467            .display_map
23468            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
23469        if cleared {
23470            cx.notify();
23471        }
23472    }
23473
23474    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
23475        (self.read_only(cx) || self.blink_manager.read(cx).visible())
23476            && self.focus_handle.is_focused(window)
23477    }
23478
23479    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
23480        self.show_cursor_when_unfocused = is_enabled;
23481        cx.notify();
23482    }
23483
23484    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
23485        cx.notify();
23486    }
23487
23488    fn on_debug_session_event(
23489        &mut self,
23490        _session: Entity<Session>,
23491        event: &SessionEvent,
23492        cx: &mut Context<Self>,
23493    ) {
23494        if let SessionEvent::InvalidateInlineValue = event {
23495            self.refresh_inline_values(cx);
23496        }
23497    }
23498
23499    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
23500        let Some(project) = self.project.clone() else {
23501            return;
23502        };
23503
23504        if !self.inline_value_cache.enabled {
23505            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
23506            self.splice_inlays(&inlays, Vec::new(), cx);
23507            return;
23508        }
23509
23510        let current_execution_position = self
23511            .highlighted_rows
23512            .get(&TypeId::of::<ActiveDebugLine>())
23513            .and_then(|lines| lines.last().map(|line| line.range.end));
23514
23515        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
23516            let inline_values = editor
23517                .update(cx, |editor, cx| {
23518                    let Some(current_execution_position) = current_execution_position else {
23519                        return Some(Task::ready(Ok(Vec::new())));
23520                    };
23521
23522                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
23523                        let snapshot = buffer.snapshot(cx);
23524
23525                        let excerpt = snapshot.excerpt_containing(
23526                            current_execution_position..current_execution_position,
23527                        )?;
23528
23529                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
23530                    })?;
23531
23532                    let range =
23533                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
23534
23535                    project.inline_values(buffer, range, cx)
23536                })
23537                .ok()
23538                .flatten()?
23539                .await
23540                .context("refreshing debugger inlays")
23541                .log_err()?;
23542
23543            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
23544
23545            for (buffer_id, inline_value) in inline_values
23546                .into_iter()
23547                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
23548            {
23549                buffer_inline_values
23550                    .entry(buffer_id)
23551                    .or_default()
23552                    .push(inline_value);
23553            }
23554
23555            editor
23556                .update(cx, |editor, cx| {
23557                    let snapshot = editor.buffer.read(cx).snapshot(cx);
23558                    let mut new_inlays = Vec::default();
23559
23560                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
23561                        let buffer_id = buffer_snapshot.remote_id();
23562                        buffer_inline_values
23563                            .get(&buffer_id)
23564                            .into_iter()
23565                            .flatten()
23566                            .for_each(|hint| {
23567                                let inlay = Inlay::debugger(
23568                                    post_inc(&mut editor.next_inlay_id),
23569                                    Anchor::in_buffer(excerpt_id, hint.position),
23570                                    hint.text(),
23571                                );
23572                                if !inlay.text().chars().contains(&'\n') {
23573                                    new_inlays.push(inlay);
23574                                }
23575                            });
23576                    }
23577
23578                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
23579                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
23580
23581                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
23582                })
23583                .ok()?;
23584            Some(())
23585        });
23586    }
23587
23588    fn on_buffer_event(
23589        &mut self,
23590        multibuffer: &Entity<MultiBuffer>,
23591        event: &multi_buffer::Event,
23592        window: &mut Window,
23593        cx: &mut Context<Self>,
23594    ) {
23595        match event {
23596            multi_buffer::Event::Edited { edited_buffer } => {
23597                self.scrollbar_marker_state.dirty = true;
23598                self.active_indent_guides_state.dirty = true;
23599                self.refresh_active_diagnostics(cx);
23600                self.refresh_code_actions(window, cx);
23601                self.refresh_single_line_folds(window, cx);
23602                self.refresh_matching_bracket_highlights(window, cx);
23603                if self.has_active_edit_prediction() {
23604                    self.update_visible_edit_prediction(window, cx);
23605                }
23606
23607                // Clean up orphaned review comments after edits
23608                self.cleanup_orphaned_review_comments(cx);
23609
23610                if let Some(buffer) = edited_buffer {
23611                    if buffer.read(cx).file().is_none() {
23612                        cx.emit(EditorEvent::TitleChanged);
23613                    }
23614
23615                    if self.project.is_some() {
23616                        let buffer_id = buffer.read(cx).remote_id();
23617                        self.register_buffer(buffer_id, cx);
23618                        self.update_lsp_data(Some(buffer_id), window, cx);
23619                        self.refresh_inlay_hints(
23620                            InlayHintRefreshReason::BufferEdited(buffer_id),
23621                            cx,
23622                        );
23623                    }
23624                }
23625
23626                cx.emit(EditorEvent::BufferEdited);
23627                cx.emit(SearchEvent::MatchesInvalidated);
23628
23629                let Some(project) = &self.project else { return };
23630                let (telemetry, is_via_ssh) = {
23631                    let project = project.read(cx);
23632                    let telemetry = project.client().telemetry().clone();
23633                    let is_via_ssh = project.is_via_remote_server();
23634                    (telemetry, is_via_ssh)
23635                };
23636                telemetry.log_edit_event("editor", is_via_ssh);
23637            }
23638            multi_buffer::Event::ExcerptsAdded {
23639                buffer,
23640                predecessor,
23641                excerpts,
23642            } => {
23643                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23644                let buffer_id = buffer.read(cx).remote_id();
23645                if self.buffer.read(cx).diff_for(buffer_id).is_none()
23646                    && let Some(project) = &self.project
23647                {
23648                    update_uncommitted_diff_for_buffer(
23649                        cx.entity(),
23650                        project,
23651                        [buffer.clone()],
23652                        self.buffer.clone(),
23653                        cx,
23654                    )
23655                    .detach();
23656                }
23657                self.update_lsp_data(Some(buffer_id), window, cx);
23658                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
23659                self.colorize_brackets(false, cx);
23660                self.refresh_selected_text_highlights(true, window, cx);
23661                cx.emit(EditorEvent::ExcerptsAdded {
23662                    buffer: buffer.clone(),
23663                    predecessor: *predecessor,
23664                    excerpts: excerpts.clone(),
23665                });
23666            }
23667            multi_buffer::Event::ExcerptsRemoved {
23668                ids,
23669                removed_buffer_ids,
23670            } => {
23671                if let Some(inlay_hints) = &mut self.inlay_hints {
23672                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
23673                }
23674                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
23675                for buffer_id in removed_buffer_ids {
23676                    self.registered_buffers.remove(buffer_id);
23677                }
23678                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23679                cx.emit(EditorEvent::ExcerptsRemoved {
23680                    ids: ids.clone(),
23681                    removed_buffer_ids: removed_buffer_ids.clone(),
23682                });
23683            }
23684            multi_buffer::Event::ExcerptsEdited {
23685                excerpt_ids,
23686                buffer_ids,
23687            } => {
23688                self.display_map.update(cx, |map, cx| {
23689                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
23690                });
23691                cx.emit(EditorEvent::ExcerptsEdited {
23692                    ids: excerpt_ids.clone(),
23693                });
23694            }
23695            multi_buffer::Event::ExcerptsExpanded { ids } => {
23696                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
23697                self.refresh_document_highlights(cx);
23698                for id in ids {
23699                    self.fetched_tree_sitter_chunks.remove(id);
23700                }
23701                self.colorize_brackets(false, cx);
23702                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
23703            }
23704            multi_buffer::Event::Reparsed(buffer_id) => {
23705                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23706                self.refresh_selected_text_highlights(true, window, cx);
23707                self.colorize_brackets(true, cx);
23708                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23709
23710                cx.emit(EditorEvent::Reparsed(*buffer_id));
23711            }
23712            multi_buffer::Event::DiffHunksToggled => {
23713                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23714            }
23715            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
23716                if !is_fresh_language {
23717                    self.registered_buffers.remove(&buffer_id);
23718                }
23719                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23720                cx.emit(EditorEvent::Reparsed(*buffer_id));
23721                cx.notify();
23722            }
23723            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
23724            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
23725            multi_buffer::Event::FileHandleChanged
23726            | multi_buffer::Event::Reloaded
23727            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
23728            multi_buffer::Event::DiagnosticsUpdated => {
23729                self.update_diagnostics_state(window, cx);
23730            }
23731            _ => {}
23732        };
23733    }
23734
23735    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
23736        if !self.diagnostics_enabled() {
23737            return;
23738        }
23739        self.refresh_active_diagnostics(cx);
23740        self.refresh_inline_diagnostics(true, window, cx);
23741        self.scrollbar_marker_state.dirty = true;
23742        cx.notify();
23743    }
23744
23745    pub fn start_temporary_diff_override(&mut self) {
23746        self.load_diff_task.take();
23747        self.temporary_diff_override = true;
23748    }
23749
23750    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
23751        self.temporary_diff_override = false;
23752        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
23753        self.buffer.update(cx, |buffer, cx| {
23754            buffer.set_all_diff_hunks_collapsed(cx);
23755        });
23756
23757        if let Some(project) = self.project.clone() {
23758            self.load_diff_task = Some(
23759                update_uncommitted_diff_for_buffer(
23760                    cx.entity(),
23761                    &project,
23762                    self.buffer.read(cx).all_buffers(),
23763                    self.buffer.clone(),
23764                    cx,
23765                )
23766                .shared(),
23767            );
23768        }
23769    }
23770
23771    fn on_display_map_changed(
23772        &mut self,
23773        _: Entity<DisplayMap>,
23774        _: &mut Window,
23775        cx: &mut Context<Self>,
23776    ) {
23777        cx.notify();
23778    }
23779
23780    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
23781        if !self.mode.is_full() {
23782            return None;
23783        }
23784
23785        let theme_settings = theme::ThemeSettings::get_global(cx);
23786        let theme = cx.theme();
23787        let accent_colors = theme.accents().clone();
23788
23789        let accent_overrides = theme_settings
23790            .theme_overrides
23791            .get(theme.name.as_ref())
23792            .map(|theme_style| &theme_style.accents)
23793            .into_iter()
23794            .flatten()
23795            .chain(
23796                theme_settings
23797                    .experimental_theme_overrides
23798                    .as_ref()
23799                    .map(|overrides| &overrides.accents)
23800                    .into_iter()
23801                    .flatten(),
23802            )
23803            .flat_map(|accent| accent.0.clone().map(SharedString::from))
23804            .collect();
23805
23806        Some(AccentData {
23807            colors: accent_colors,
23808            overrides: accent_overrides,
23809        })
23810    }
23811
23812    fn fetch_applicable_language_settings(
23813        &self,
23814        cx: &App,
23815    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
23816        if !self.mode.is_full() {
23817            return HashMap::default();
23818        }
23819
23820        self.buffer().read(cx).all_buffers().into_iter().fold(
23821            HashMap::default(),
23822            |mut acc, buffer| {
23823                let buffer = buffer.read(cx);
23824                let language = buffer.language().map(|language| language.name());
23825                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
23826                    let file = buffer.file();
23827                    v.insert(language_settings(language, file, cx).into_owned());
23828                }
23829                acc
23830            },
23831        )
23832    }
23833
23834    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
23835        let new_language_settings = self.fetch_applicable_language_settings(cx);
23836        let language_settings_changed = new_language_settings != self.applicable_language_settings;
23837        self.applicable_language_settings = new_language_settings;
23838
23839        let new_accents = self.fetch_accent_data(cx);
23840        let accents_changed = new_accents != self.accent_data;
23841        self.accent_data = new_accents;
23842
23843        if self.diagnostics_enabled() {
23844            let new_severity = EditorSettings::get_global(cx)
23845                .diagnostics_max_severity
23846                .unwrap_or(DiagnosticSeverity::Hint);
23847            self.set_max_diagnostics_severity(new_severity, cx);
23848        }
23849        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23850        self.update_edit_prediction_settings(cx);
23851        self.refresh_edit_prediction(true, false, window, cx);
23852        self.refresh_inline_values(cx);
23853        self.refresh_inlay_hints(
23854            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
23855                self.selections.newest_anchor().head(),
23856                &self.buffer.read(cx).snapshot(cx),
23857                cx,
23858            )),
23859            cx,
23860        );
23861
23862        let old_cursor_shape = self.cursor_shape;
23863        let old_show_breadcrumbs = self.show_breadcrumbs;
23864
23865        {
23866            let editor_settings = EditorSettings::get_global(cx);
23867            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
23868            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
23869            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
23870            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
23871        }
23872
23873        if old_cursor_shape != self.cursor_shape {
23874            cx.emit(EditorEvent::CursorShapeChanged);
23875        }
23876
23877        if old_show_breadcrumbs != self.show_breadcrumbs {
23878            cx.emit(EditorEvent::BreadcrumbsChanged);
23879        }
23880
23881        let project_settings = ProjectSettings::get_global(cx);
23882        self.buffer_serialization = self
23883            .should_serialize_buffer()
23884            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
23885
23886        if self.mode.is_full() {
23887            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
23888            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
23889            if self.show_inline_diagnostics != show_inline_diagnostics {
23890                self.show_inline_diagnostics = show_inline_diagnostics;
23891                self.refresh_inline_diagnostics(false, window, cx);
23892            }
23893
23894            if self.git_blame_inline_enabled != inline_blame_enabled {
23895                self.toggle_git_blame_inline_internal(false, window, cx);
23896            }
23897
23898            let minimap_settings = EditorSettings::get_global(cx).minimap;
23899            if self.minimap_visibility != MinimapVisibility::Disabled {
23900                if self.minimap_visibility.settings_visibility()
23901                    != minimap_settings.minimap_enabled()
23902                {
23903                    self.set_minimap_visibility(
23904                        MinimapVisibility::for_mode(self.mode(), cx),
23905                        window,
23906                        cx,
23907                    );
23908                } else if let Some(minimap_entity) = self.minimap.as_ref() {
23909                    minimap_entity.update(cx, |minimap_editor, cx| {
23910                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
23911                    })
23912                }
23913            }
23914
23915            if language_settings_changed || accents_changed {
23916                self.colorize_brackets(true, cx);
23917            }
23918
23919            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
23920                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
23921            }) {
23922                if !inlay_splice.is_empty() {
23923                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
23924                }
23925                self.refresh_colors_for_visible_range(None, window, cx);
23926            }
23927        }
23928
23929        cx.notify();
23930    }
23931
23932    fn theme_changed(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23933        if !self.mode.is_full() {
23934            return;
23935        }
23936
23937        let new_accents = self.fetch_accent_data(cx);
23938        if new_accents != self.accent_data {
23939            self.accent_data = new_accents;
23940            self.colorize_brackets(true, cx);
23941        }
23942    }
23943
23944    pub fn set_searchable(&mut self, searchable: bool) {
23945        self.searchable = searchable;
23946    }
23947
23948    pub fn searchable(&self) -> bool {
23949        self.searchable
23950    }
23951
23952    pub fn open_excerpts_in_split(
23953        &mut self,
23954        _: &OpenExcerptsSplit,
23955        window: &mut Window,
23956        cx: &mut Context<Self>,
23957    ) {
23958        self.open_excerpts_common(None, true, window, cx)
23959    }
23960
23961    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
23962        self.open_excerpts_common(None, false, window, cx)
23963    }
23964
23965    pub(crate) fn open_excerpts_common(
23966        &mut self,
23967        jump_data: Option<JumpData>,
23968        split: bool,
23969        window: &mut Window,
23970        cx: &mut Context<Self>,
23971    ) {
23972        let Some(workspace) = self.workspace() else {
23973            cx.propagate();
23974            return;
23975        };
23976
23977        if self.buffer.read(cx).is_singleton() {
23978            cx.propagate();
23979            return;
23980        }
23981
23982        let mut new_selections_by_buffer = HashMap::default();
23983        match &jump_data {
23984            Some(JumpData::MultiBufferPoint {
23985                excerpt_id,
23986                position,
23987                anchor,
23988                line_offset_from_top,
23989            }) => {
23990                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
23991                if let Some(buffer) = multi_buffer_snapshot
23992                    .buffer_id_for_excerpt(*excerpt_id)
23993                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
23994                {
23995                    let buffer_snapshot = buffer.read(cx).snapshot();
23996                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
23997                        language::ToPoint::to_point(anchor, &buffer_snapshot)
23998                    } else {
23999                        buffer_snapshot.clip_point(*position, Bias::Left)
24000                    };
24001                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
24002                    new_selections_by_buffer.insert(
24003                        buffer,
24004                        (
24005                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
24006                            Some(*line_offset_from_top),
24007                        ),
24008                    );
24009                }
24010            }
24011            Some(JumpData::MultiBufferRow {
24012                row,
24013                line_offset_from_top,
24014            }) => {
24015                let point = MultiBufferPoint::new(row.0, 0);
24016                if let Some((buffer, buffer_point, _)) =
24017                    self.buffer.read(cx).point_to_buffer_point(point, cx)
24018                {
24019                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
24020                    new_selections_by_buffer
24021                        .entry(buffer)
24022                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
24023                        .0
24024                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
24025                }
24026            }
24027            None => {
24028                let selections = self
24029                    .selections
24030                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
24031                let multi_buffer = self.buffer.read(cx);
24032                for selection in selections {
24033                    for (snapshot, range, _, anchor) in multi_buffer
24034                        .snapshot(cx)
24035                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
24036                    {
24037                        if let Some(anchor) = anchor {
24038                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
24039                            else {
24040                                continue;
24041                            };
24042                            let offset = text::ToOffset::to_offset(
24043                                &anchor.text_anchor,
24044                                &buffer_handle.read(cx).snapshot(),
24045                            );
24046                            let range = BufferOffset(offset)..BufferOffset(offset);
24047                            new_selections_by_buffer
24048                                .entry(buffer_handle)
24049                                .or_insert((Vec::new(), None))
24050                                .0
24051                                .push(range)
24052                        } else {
24053                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
24054                            else {
24055                                continue;
24056                            };
24057                            new_selections_by_buffer
24058                                .entry(buffer_handle)
24059                                .or_insert((Vec::new(), None))
24060                                .0
24061                                .push(range)
24062                        }
24063                    }
24064                }
24065            }
24066        }
24067
24068        new_selections_by_buffer
24069            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
24070
24071        if new_selections_by_buffer.is_empty() {
24072            return;
24073        }
24074
24075        // We defer the pane interaction because we ourselves are a workspace item
24076        // and activating a new item causes the pane to call a method on us reentrantly,
24077        // which panics if we're on the stack.
24078        window.defer(cx, move |window, cx| {
24079            workspace.update(cx, |workspace, cx| {
24080                let pane = if split {
24081                    workspace.adjacent_pane(window, cx)
24082                } else {
24083                    workspace.active_pane().clone()
24084                };
24085
24086                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
24087                    let buffer_read = buffer.read(cx);
24088                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
24089                        (true, project::File::from_dyn(Some(file)).is_some())
24090                    } else {
24091                        (false, false)
24092                    };
24093
24094                    // If project file is none workspace.open_project_item will fail to open the excerpt
24095                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
24096                    // so we check if there's a tab match in that case first
24097                    let editor = (!has_file || !is_project_file)
24098                        .then(|| {
24099                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
24100                            // so `workspace.open_project_item` will never find them, always opening a new editor.
24101                            // Instead, we try to activate the existing editor in the pane first.
24102                            let (editor, pane_item_index, pane_item_id) =
24103                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
24104                                    let editor = item.downcast::<Editor>()?;
24105                                    let singleton_buffer =
24106                                        editor.read(cx).buffer().read(cx).as_singleton()?;
24107                                    if singleton_buffer == buffer {
24108                                        Some((editor, i, item.item_id()))
24109                                    } else {
24110                                        None
24111                                    }
24112                                })?;
24113                            pane.update(cx, |pane, cx| {
24114                                pane.activate_item(pane_item_index, true, true, window, cx);
24115                                if !PreviewTabsSettings::get_global(cx)
24116                                    .enable_preview_from_multibuffer
24117                                {
24118                                    pane.unpreview_item_if_preview(pane_item_id);
24119                                }
24120                            });
24121                            Some(editor)
24122                        })
24123                        .flatten()
24124                        .unwrap_or_else(|| {
24125                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
24126                                .enable_keep_preview_on_code_navigation;
24127                            let allow_new_preview =
24128                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
24129                            workspace.open_project_item::<Self>(
24130                                pane.clone(),
24131                                buffer,
24132                                true,
24133                                true,
24134                                keep_old_preview,
24135                                allow_new_preview,
24136                                window,
24137                                cx,
24138                            )
24139                        });
24140
24141                    editor.update(cx, |editor, cx| {
24142                        if has_file && !is_project_file {
24143                            editor.set_read_only(true);
24144                        }
24145                        let autoscroll = match scroll_offset {
24146                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
24147                            None => Autoscroll::newest(),
24148                        };
24149                        let nav_history = editor.nav_history.take();
24150                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
24151                        let Some((&excerpt_id, _, buffer_snapshot)) =
24152                            multibuffer_snapshot.as_singleton()
24153                        else {
24154                            return;
24155                        };
24156                        editor.change_selections(
24157                            SelectionEffects::scroll(autoscroll),
24158                            window,
24159                            cx,
24160                            |s| {
24161                                s.select_ranges(ranges.into_iter().map(|range| {
24162                                    let range = buffer_snapshot.anchor_before(range.start)
24163                                        ..buffer_snapshot.anchor_after(range.end);
24164                                    multibuffer_snapshot
24165                                        .anchor_range_in_excerpt(excerpt_id, range)
24166                                        .unwrap()
24167                                }));
24168                            },
24169                        );
24170                        editor.nav_history = nav_history;
24171                    });
24172                }
24173            })
24174        });
24175    }
24176
24177    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
24178        let snapshot = self.buffer.read(cx).read(cx);
24179        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
24180        Some(
24181            ranges
24182                .iter()
24183                .map(move |range| {
24184                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
24185                })
24186                .collect(),
24187        )
24188    }
24189
24190    fn selection_replacement_ranges(
24191        &self,
24192        range: Range<MultiBufferOffsetUtf16>,
24193        cx: &mut App,
24194    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
24195        let selections = self
24196            .selections
24197            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24198        let newest_selection = selections
24199            .iter()
24200            .max_by_key(|selection| selection.id)
24201            .unwrap();
24202        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
24203        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
24204        let snapshot = self.buffer.read(cx).read(cx);
24205        selections
24206            .into_iter()
24207            .map(|mut selection| {
24208                selection.start.0.0 =
24209                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
24210                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
24211                snapshot.clip_offset_utf16(selection.start, Bias::Left)
24212                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
24213            })
24214            .collect()
24215    }
24216
24217    fn report_editor_event(
24218        &self,
24219        reported_event: ReportEditorEvent,
24220        file_extension: Option<String>,
24221        cx: &App,
24222    ) {
24223        if cfg!(any(test, feature = "test-support")) {
24224            return;
24225        }
24226
24227        let Some(project) = &self.project else { return };
24228
24229        // If None, we are in a file without an extension
24230        let file = self
24231            .buffer
24232            .read(cx)
24233            .as_singleton()
24234            .and_then(|b| b.read(cx).file());
24235        let file_extension = file_extension.or(file
24236            .as_ref()
24237            .and_then(|file| Path::new(file.file_name(cx)).extension())
24238            .and_then(|e| e.to_str())
24239            .map(|a| a.to_string()));
24240
24241        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
24242            .map(|vim_mode| vim_mode.0)
24243            .unwrap_or(false);
24244
24245        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
24246        let copilot_enabled = edit_predictions_provider
24247            == language::language_settings::EditPredictionProvider::Copilot;
24248        let copilot_enabled_for_language = self
24249            .buffer
24250            .read(cx)
24251            .language_settings(cx)
24252            .show_edit_predictions;
24253
24254        let project = project.read(cx);
24255        let event_type = reported_event.event_type();
24256
24257        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
24258            telemetry::event!(
24259                event_type,
24260                type = if auto_saved {"autosave"} else {"manual"},
24261                file_extension,
24262                vim_mode,
24263                copilot_enabled,
24264                copilot_enabled_for_language,
24265                edit_predictions_provider,
24266                is_via_ssh = project.is_via_remote_server(),
24267            );
24268        } else {
24269            telemetry::event!(
24270                event_type,
24271                file_extension,
24272                vim_mode,
24273                copilot_enabled,
24274                copilot_enabled_for_language,
24275                edit_predictions_provider,
24276                is_via_ssh = project.is_via_remote_server(),
24277            );
24278        };
24279    }
24280
24281    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
24282    /// with each line being an array of {text, highlight} objects.
24283    fn copy_highlight_json(
24284        &mut self,
24285        _: &CopyHighlightJson,
24286        window: &mut Window,
24287        cx: &mut Context<Self>,
24288    ) {
24289        #[derive(Serialize)]
24290        struct Chunk<'a> {
24291            text: String,
24292            highlight: Option<&'a str>,
24293        }
24294
24295        let snapshot = self.buffer.read(cx).snapshot(cx);
24296        let range = self
24297            .selected_text_range(false, window, cx)
24298            .and_then(|selection| {
24299                if selection.range.is_empty() {
24300                    None
24301                } else {
24302                    Some(
24303                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
24304                            selection.range.start,
24305                        )))
24306                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
24307                                selection.range.end,
24308                            ))),
24309                    )
24310                }
24311            })
24312            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
24313
24314        let chunks = snapshot.chunks(range, true);
24315        let mut lines = Vec::new();
24316        let mut line: VecDeque<Chunk> = VecDeque::new();
24317
24318        let Some(style) = self.style.as_ref() else {
24319            return;
24320        };
24321
24322        for chunk in chunks {
24323            let highlight = chunk
24324                .syntax_highlight_id
24325                .and_then(|id| id.name(&style.syntax));
24326            let mut chunk_lines = chunk.text.split('\n').peekable();
24327            while let Some(text) = chunk_lines.next() {
24328                let mut merged_with_last_token = false;
24329                if let Some(last_token) = line.back_mut()
24330                    && last_token.highlight == highlight
24331                {
24332                    last_token.text.push_str(text);
24333                    merged_with_last_token = true;
24334                }
24335
24336                if !merged_with_last_token {
24337                    line.push_back(Chunk {
24338                        text: text.into(),
24339                        highlight,
24340                    });
24341                }
24342
24343                if chunk_lines.peek().is_some() {
24344                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
24345                        line.pop_front();
24346                    }
24347                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
24348                        line.pop_back();
24349                    }
24350
24351                    lines.push(mem::take(&mut line));
24352                }
24353            }
24354        }
24355
24356        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
24357            return;
24358        };
24359        cx.write_to_clipboard(ClipboardItem::new_string(lines));
24360    }
24361
24362    pub fn open_context_menu(
24363        &mut self,
24364        _: &OpenContextMenu,
24365        window: &mut Window,
24366        cx: &mut Context<Self>,
24367    ) {
24368        self.request_autoscroll(Autoscroll::newest(), cx);
24369        let position = self
24370            .selections
24371            .newest_display(&self.display_snapshot(cx))
24372            .start;
24373        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
24374    }
24375
24376    pub fn replay_insert_event(
24377        &mut self,
24378        text: &str,
24379        relative_utf16_range: Option<Range<isize>>,
24380        window: &mut Window,
24381        cx: &mut Context<Self>,
24382    ) {
24383        if !self.input_enabled {
24384            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24385            return;
24386        }
24387        if let Some(relative_utf16_range) = relative_utf16_range {
24388            let selections = self
24389                .selections
24390                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24391            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24392                let new_ranges = selections.into_iter().map(|range| {
24393                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
24394                        range
24395                            .head()
24396                            .0
24397                            .0
24398                            .saturating_add_signed(relative_utf16_range.start),
24399                    ));
24400                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
24401                        range
24402                            .head()
24403                            .0
24404                            .0
24405                            .saturating_add_signed(relative_utf16_range.end),
24406                    ));
24407                    start..end
24408                });
24409                s.select_ranges(new_ranges);
24410            });
24411        }
24412
24413        self.handle_input(text, window, cx);
24414    }
24415
24416    pub fn is_focused(&self, window: &Window) -> bool {
24417        self.focus_handle.is_focused(window)
24418    }
24419
24420    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24421        cx.emit(EditorEvent::Focused);
24422
24423        if let Some(descendant) = self
24424            .last_focused_descendant
24425            .take()
24426            .and_then(|descendant| descendant.upgrade())
24427        {
24428            window.focus(&descendant, cx);
24429        } else {
24430            if let Some(blame) = self.blame.as_ref() {
24431                blame.update(cx, GitBlame::focus)
24432            }
24433
24434            self.blink_manager.update(cx, BlinkManager::enable);
24435            self.show_cursor_names(window, cx);
24436            self.buffer.update(cx, |buffer, cx| {
24437                buffer.finalize_last_transaction(cx);
24438                if self.leader_id.is_none() {
24439                    buffer.set_active_selections(
24440                        &self.selections.disjoint_anchors_arc(),
24441                        self.selections.line_mode(),
24442                        self.cursor_shape,
24443                        cx,
24444                    );
24445                }
24446            });
24447
24448            if let Some(position_map) = self.last_position_map.clone() {
24449                EditorElement::mouse_moved(
24450                    self,
24451                    &MouseMoveEvent {
24452                        position: window.mouse_position(),
24453                        pressed_button: None,
24454                        modifiers: window.modifiers(),
24455                    },
24456                    &position_map,
24457                    None,
24458                    window,
24459                    cx,
24460                );
24461            }
24462        }
24463    }
24464
24465    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24466        cx.emit(EditorEvent::FocusedIn)
24467    }
24468
24469    fn handle_focus_out(
24470        &mut self,
24471        event: FocusOutEvent,
24472        _window: &mut Window,
24473        cx: &mut Context<Self>,
24474    ) {
24475        if event.blurred != self.focus_handle {
24476            self.last_focused_descendant = Some(event.blurred);
24477        }
24478        self.selection_drag_state = SelectionDragState::None;
24479        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
24480    }
24481
24482    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24483        self.blink_manager.update(cx, BlinkManager::disable);
24484        self.buffer
24485            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
24486
24487        if let Some(blame) = self.blame.as_ref() {
24488            blame.update(cx, GitBlame::blur)
24489        }
24490        if !self.hover_state.focused(window, cx) {
24491            hide_hover(self, cx);
24492        }
24493        if !self
24494            .context_menu
24495            .borrow()
24496            .as_ref()
24497            .is_some_and(|context_menu| context_menu.focused(window, cx))
24498        {
24499            self.hide_context_menu(window, cx);
24500        }
24501        self.take_active_edit_prediction(cx);
24502        cx.emit(EditorEvent::Blurred);
24503        cx.notify();
24504    }
24505
24506    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24507        let mut pending: String = window
24508            .pending_input_keystrokes()
24509            .into_iter()
24510            .flatten()
24511            .filter_map(|keystroke| keystroke.key_char.clone())
24512            .collect();
24513
24514        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
24515            pending = "".to_string();
24516        }
24517
24518        let existing_pending = self
24519            .text_highlights::<PendingInput>(cx)
24520            .map(|(_, ranges)| ranges.to_vec());
24521        if existing_pending.is_none() && pending.is_empty() {
24522            return;
24523        }
24524        let transaction =
24525            self.transact(window, cx, |this, window, cx| {
24526                let selections = this
24527                    .selections
24528                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
24529                let edits = selections
24530                    .iter()
24531                    .map(|selection| (selection.end..selection.end, pending.clone()));
24532                this.edit(edits, cx);
24533                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24534                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
24535                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
24536                    }));
24537                });
24538                if let Some(existing_ranges) = existing_pending {
24539                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
24540                    this.edit(edits, cx);
24541                }
24542            });
24543
24544        let snapshot = self.snapshot(window, cx);
24545        let ranges = self
24546            .selections
24547            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
24548            .into_iter()
24549            .map(|selection| {
24550                snapshot.buffer_snapshot().anchor_after(selection.end)
24551                    ..snapshot
24552                        .buffer_snapshot()
24553                        .anchor_before(selection.end + pending.len())
24554            })
24555            .collect();
24556
24557        if pending.is_empty() {
24558            self.clear_highlights::<PendingInput>(cx);
24559        } else {
24560            self.highlight_text::<PendingInput>(
24561                ranges,
24562                HighlightStyle {
24563                    underline: Some(UnderlineStyle {
24564                        thickness: px(1.),
24565                        color: None,
24566                        wavy: false,
24567                    }),
24568                    ..Default::default()
24569                },
24570                cx,
24571            );
24572        }
24573
24574        self.ime_transaction = self.ime_transaction.or(transaction);
24575        if let Some(transaction) = self.ime_transaction {
24576            self.buffer.update(cx, |buffer, cx| {
24577                buffer.group_until_transaction(transaction, cx);
24578            });
24579        }
24580
24581        if self.text_highlights::<PendingInput>(cx).is_none() {
24582            self.ime_transaction.take();
24583        }
24584    }
24585
24586    pub fn register_action_renderer(
24587        &mut self,
24588        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
24589    ) -> Subscription {
24590        let id = self.next_editor_action_id.post_inc();
24591        self.editor_actions
24592            .borrow_mut()
24593            .insert(id, Box::new(listener));
24594
24595        let editor_actions = self.editor_actions.clone();
24596        Subscription::new(move || {
24597            editor_actions.borrow_mut().remove(&id);
24598        })
24599    }
24600
24601    pub fn register_action<A: Action>(
24602        &mut self,
24603        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
24604    ) -> Subscription {
24605        let id = self.next_editor_action_id.post_inc();
24606        let listener = Arc::new(listener);
24607        self.editor_actions.borrow_mut().insert(
24608            id,
24609            Box::new(move |_, window, _| {
24610                let listener = listener.clone();
24611                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
24612                    let action = action.downcast_ref().unwrap();
24613                    if phase == DispatchPhase::Bubble {
24614                        listener(action, window, cx)
24615                    }
24616                })
24617            }),
24618        );
24619
24620        let editor_actions = self.editor_actions.clone();
24621        Subscription::new(move || {
24622            editor_actions.borrow_mut().remove(&id);
24623        })
24624    }
24625
24626    pub fn file_header_size(&self) -> u32 {
24627        FILE_HEADER_HEIGHT
24628    }
24629
24630    pub fn restore(
24631        &mut self,
24632        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
24633        window: &mut Window,
24634        cx: &mut Context<Self>,
24635    ) {
24636        self.buffer().update(cx, |multi_buffer, cx| {
24637            for (buffer_id, changes) in revert_changes {
24638                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
24639                    buffer.update(cx, |buffer, cx| {
24640                        buffer.edit(
24641                            changes
24642                                .into_iter()
24643                                .map(|(range, text)| (range, text.to_string())),
24644                            None,
24645                            cx,
24646                        );
24647                    });
24648                }
24649            }
24650        });
24651        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24652            selections.refresh()
24653        });
24654    }
24655
24656    pub fn to_pixel_point(
24657        &mut self,
24658        source: multi_buffer::Anchor,
24659        editor_snapshot: &EditorSnapshot,
24660        window: &mut Window,
24661        cx: &App,
24662    ) -> Option<gpui::Point<Pixels>> {
24663        let source_point = source.to_display_point(editor_snapshot);
24664        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
24665    }
24666
24667    pub fn display_to_pixel_point(
24668        &mut self,
24669        source: DisplayPoint,
24670        editor_snapshot: &EditorSnapshot,
24671        window: &mut Window,
24672        cx: &App,
24673    ) -> Option<gpui::Point<Pixels>> {
24674        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
24675        let text_layout_details = self.text_layout_details(window);
24676        let scroll_top = text_layout_details
24677            .scroll_anchor
24678            .scroll_position(editor_snapshot)
24679            .y;
24680
24681        if source.row().as_f64() < scroll_top.floor() {
24682            return None;
24683        }
24684        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
24685        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
24686        Some(gpui::Point::new(source_x, source_y))
24687    }
24688
24689    pub fn has_visible_completions_menu(&self) -> bool {
24690        !self.edit_prediction_preview_is_active()
24691            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
24692                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
24693            })
24694    }
24695
24696    pub fn register_addon<T: Addon>(&mut self, instance: T) {
24697        if self.mode.is_minimap() {
24698            return;
24699        }
24700        self.addons
24701            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
24702    }
24703
24704    pub fn unregister_addon<T: Addon>(&mut self) {
24705        self.addons.remove(&std::any::TypeId::of::<T>());
24706    }
24707
24708    pub fn addon<T: Addon>(&self) -> Option<&T> {
24709        let type_id = std::any::TypeId::of::<T>();
24710        self.addons
24711            .get(&type_id)
24712            .and_then(|item| item.to_any().downcast_ref::<T>())
24713    }
24714
24715    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
24716        let type_id = std::any::TypeId::of::<T>();
24717        self.addons
24718            .get_mut(&type_id)
24719            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
24720    }
24721
24722    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
24723        let text_layout_details = self.text_layout_details(window);
24724        let style = &text_layout_details.editor_style;
24725        let font_id = window.text_system().resolve_font(&style.text.font());
24726        let font_size = style.text.font_size.to_pixels(window.rem_size());
24727        let line_height = style.text.line_height_in_pixels(window.rem_size());
24728        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
24729        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
24730
24731        CharacterDimensions {
24732            em_width,
24733            em_advance,
24734            line_height,
24735        }
24736    }
24737
24738    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
24739        self.load_diff_task.clone()
24740    }
24741
24742    fn read_metadata_from_db(
24743        &mut self,
24744        item_id: u64,
24745        workspace_id: WorkspaceId,
24746        window: &mut Window,
24747        cx: &mut Context<Editor>,
24748    ) {
24749        if self.buffer_kind(cx) == ItemBufferKind::Singleton
24750            && !self.mode.is_minimap()
24751            && WorkspaceSettings::get(None, cx).restore_on_startup
24752                != RestoreOnStartupBehavior::EmptyTab
24753        {
24754            let buffer_snapshot = OnceCell::new();
24755
24756            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
24757                && !folds.is_empty()
24758            {
24759                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
24760                let snapshot_len = snapshot.len().0;
24761
24762                // Helper: search for fingerprint in buffer, return offset if found
24763                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
24764                    // Ensure we start at a character boundary (defensive)
24765                    let search_start = snapshot
24766                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
24767                        .0;
24768                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
24769
24770                    let mut byte_offset = search_start;
24771                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
24772                        if byte_offset > search_end {
24773                            break;
24774                        }
24775                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
24776                            return Some(byte_offset);
24777                        }
24778                        byte_offset += ch.len_utf8();
24779                    }
24780                    None
24781                };
24782
24783                // Track search position to handle duplicate fingerprints correctly.
24784                // Folds are stored in document order, so we advance after each match.
24785                let mut search_start = 0usize;
24786
24787                let valid_folds: Vec<_> = folds
24788                    .into_iter()
24789                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
24790                        // Skip folds without fingerprints (old data before migration)
24791                        let sfp = start_fp?;
24792                        let efp = end_fp?;
24793                        let efp_len = efp.len();
24794
24795                        // Fast path: check if fingerprints match at stored offsets
24796                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
24797                        let start_matches = stored_start < snapshot_len
24798                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
24799                        let efp_check_pos = stored_end.saturating_sub(efp_len);
24800                        let end_matches = efp_check_pos >= stored_start
24801                            && stored_end <= snapshot_len
24802                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
24803
24804                        let (new_start, new_end) = if start_matches && end_matches {
24805                            // Offsets unchanged, use stored values
24806                            (stored_start, stored_end)
24807                        } else if sfp == efp {
24808                            // Short fold: identical fingerprints can only match once per search
24809                            // Use stored fold length to compute new_end
24810                            let new_start = find_fingerprint(&sfp, search_start)?;
24811                            let fold_len = stored_end - stored_start;
24812                            let new_end = new_start + fold_len;
24813                            (new_start, new_end)
24814                        } else {
24815                            // Slow path: search for fingerprints in buffer
24816                            let new_start = find_fingerprint(&sfp, search_start)?;
24817                            // Search for end_fp after start, then add efp_len to get actual fold end
24818                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
24819                            let new_end = efp_pos + efp_len;
24820                            (new_start, new_end)
24821                        };
24822
24823                        // Advance search position for next fold
24824                        search_start = new_end;
24825
24826                        // Validate fold makes sense (end must be after start)
24827                        if new_end <= new_start {
24828                            return None;
24829                        }
24830
24831                        Some(
24832                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
24833                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
24834                        )
24835                    })
24836                    .collect();
24837
24838                if !valid_folds.is_empty() {
24839                    self.fold_ranges(valid_folds, false, window, cx);
24840
24841                    // Migrate folds to current entity_id before workspace cleanup runs.
24842                    // Entity IDs change between sessions, but workspace cleanup deletes
24843                    // old editor rows (cascading to folds) based on current entity IDs.
24844                    let new_editor_id = cx.entity().entity_id().as_u64() as ItemId;
24845                    if new_editor_id != item_id {
24846                        cx.spawn(async move |_, _| {
24847                            DB.migrate_editor_folds(item_id, new_editor_id, workspace_id)
24848                                .await
24849                                .log_err();
24850                        })
24851                        .detach();
24852                    }
24853                }
24854            }
24855
24856            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
24857                && !selections.is_empty()
24858            {
24859                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
24860                // skip adding the initial selection to selection history
24861                self.selection_history.mode = SelectionHistoryMode::Skipping;
24862                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24863                    s.select_ranges(selections.into_iter().map(|(start, end)| {
24864                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
24865                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
24866                    }));
24867                });
24868                self.selection_history.mode = SelectionHistoryMode::Normal;
24869            };
24870        }
24871
24872        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
24873    }
24874
24875    fn update_lsp_data(
24876        &mut self,
24877        for_buffer: Option<BufferId>,
24878        window: &mut Window,
24879        cx: &mut Context<'_, Self>,
24880    ) {
24881        if let Some(buffer_id) = for_buffer {
24882            self.pull_diagnostics(buffer_id, window, cx);
24883        }
24884        self.refresh_colors_for_visible_range(for_buffer, window, cx);
24885    }
24886
24887    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
24888        if self.ignore_lsp_data() {
24889            return;
24890        }
24891        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
24892            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
24893        }
24894    }
24895
24896    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
24897        if self.ignore_lsp_data() {
24898            return;
24899        }
24900
24901        if !self.registered_buffers.contains_key(&buffer_id)
24902            && let Some(project) = self.project.as_ref()
24903        {
24904            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
24905                project.update(cx, |project, cx| {
24906                    self.registered_buffers.insert(
24907                        buffer_id,
24908                        project.register_buffer_with_language_servers(&buffer, cx),
24909                    );
24910                });
24911            } else {
24912                self.registered_buffers.remove(&buffer_id);
24913            }
24914        }
24915    }
24916
24917    fn ignore_lsp_data(&self) -> bool {
24918        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
24919        // skip any LSP updates for it.
24920        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
24921    }
24922
24923    pub(crate) fn create_style(&self, cx: &App) -> EditorStyle {
24924        let settings = ThemeSettings::get_global(cx);
24925
24926        let mut text_style = match self.mode {
24927            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24928                color: cx.theme().colors().editor_foreground,
24929                font_family: settings.ui_font.family.clone(),
24930                font_features: settings.ui_font.features.clone(),
24931                font_fallbacks: settings.ui_font.fallbacks.clone(),
24932                font_size: rems(0.875).into(),
24933                font_weight: settings.ui_font.weight,
24934                line_height: relative(settings.buffer_line_height.value()),
24935                ..Default::default()
24936            },
24937            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24938                color: cx.theme().colors().editor_foreground,
24939                font_family: settings.buffer_font.family.clone(),
24940                font_features: settings.buffer_font.features.clone(),
24941                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24942                font_size: settings.buffer_font_size(cx).into(),
24943                font_weight: settings.buffer_font.weight,
24944                line_height: relative(settings.buffer_line_height.value()),
24945                ..Default::default()
24946            },
24947        };
24948        if let Some(text_style_refinement) = &self.text_style_refinement {
24949            text_style.refine(text_style_refinement)
24950        }
24951
24952        let background = match self.mode {
24953            EditorMode::SingleLine => cx.theme().system().transparent,
24954            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24955            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24956            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24957        };
24958
24959        EditorStyle {
24960            background,
24961            border: cx.theme().colors().border,
24962            local_player: cx.theme().players().local(),
24963            text: text_style,
24964            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24965            syntax: cx.theme().syntax().clone(),
24966            status: cx.theme().status().clone(),
24967            inlay_hints_style: make_inlay_hints_style(cx),
24968            edit_prediction_styles: make_suggestion_styles(cx),
24969            unnecessary_code_fade: settings.unnecessary_code_fade,
24970            show_underlines: self.diagnostics_enabled(),
24971        }
24972    }
24973    fn breadcrumbs_inner(&self, variant: &Theme, cx: &App) -> Option<Vec<BreadcrumbText>> {
24974        let cursor = self.selections.newest_anchor().head();
24975        let multibuffer = self.buffer().read(cx);
24976        let is_singleton = multibuffer.is_singleton();
24977        let (buffer_id, symbols) = multibuffer
24978            .read(cx)
24979            .symbols_containing(cursor, Some(variant.syntax()))?;
24980        let buffer = multibuffer.buffer(buffer_id)?;
24981
24982        let buffer = buffer.read(cx);
24983        let settings = ThemeSettings::get_global(cx);
24984        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
24985        let mut breadcrumbs = if is_singleton {
24986            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
24987                buffer
24988                    .snapshot()
24989                    .resolve_file_path(
24990                        self.project
24991                            .as_ref()
24992                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
24993                            .unwrap_or_default(),
24994                        cx,
24995                    )
24996                    .unwrap_or_else(|| {
24997                        if multibuffer.is_singleton() {
24998                            multibuffer.title(cx).to_string()
24999                        } else {
25000                            "untitled".to_string()
25001                        }
25002                    })
25003            });
25004            vec![BreadcrumbText {
25005                text,
25006                highlights: None,
25007                font: Some(settings.buffer_font.clone()),
25008            }]
25009        } else {
25010            vec![]
25011        };
25012
25013        breadcrumbs.extend(symbols.into_iter().map(|symbol| BreadcrumbText {
25014            text: symbol.text,
25015            highlights: Some(symbol.highlight_ranges),
25016            font: Some(settings.buffer_font.clone()),
25017        }));
25018        Some(breadcrumbs)
25019    }
25020}
25021
25022fn edit_for_markdown_paste<'a>(
25023    buffer: &MultiBufferSnapshot,
25024    range: Range<MultiBufferOffset>,
25025    to_insert: &'a str,
25026    url: Option<url::Url>,
25027) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
25028    if url.is_none() {
25029        return (range, Cow::Borrowed(to_insert));
25030    };
25031
25032    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
25033
25034    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
25035        Cow::Borrowed(to_insert)
25036    } else {
25037        Cow::Owned(format!("[{old_text}]({to_insert})"))
25038    };
25039    (range, new_text)
25040}
25041
25042fn process_completion_for_edit(
25043    completion: &Completion,
25044    intent: CompletionIntent,
25045    buffer: &Entity<Buffer>,
25046    cursor_position: &text::Anchor,
25047    cx: &mut Context<Editor>,
25048) -> CompletionEdit {
25049    let buffer = buffer.read(cx);
25050    let buffer_snapshot = buffer.snapshot();
25051    let (snippet, new_text) = if completion.is_snippet() {
25052        let mut snippet_source = completion.new_text.clone();
25053        // Workaround for typescript language server issues so that methods don't expand within
25054        // strings and functions with type expressions. The previous point is used because the query
25055        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
25056        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
25057        let previous_point = if previous_point.column > 0 {
25058            cursor_position.to_previous_offset(&buffer_snapshot)
25059        } else {
25060            cursor_position.to_offset(&buffer_snapshot)
25061        };
25062        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
25063            && scope.prefers_label_for_snippet_in_completion()
25064            && let Some(label) = completion.label()
25065            && matches!(
25066                completion.kind(),
25067                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
25068            )
25069        {
25070            snippet_source = label;
25071        }
25072        match Snippet::parse(&snippet_source).log_err() {
25073            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
25074            None => (None, completion.new_text.clone()),
25075        }
25076    } else {
25077        (None, completion.new_text.clone())
25078    };
25079
25080    let mut range_to_replace = {
25081        let replace_range = &completion.replace_range;
25082        if let CompletionSource::Lsp {
25083            insert_range: Some(insert_range),
25084            ..
25085        } = &completion.source
25086        {
25087            debug_assert_eq!(
25088                insert_range.start, replace_range.start,
25089                "insert_range and replace_range should start at the same position"
25090            );
25091            debug_assert!(
25092                insert_range
25093                    .start
25094                    .cmp(cursor_position, &buffer_snapshot)
25095                    .is_le(),
25096                "insert_range should start before or at cursor position"
25097            );
25098            debug_assert!(
25099                replace_range
25100                    .start
25101                    .cmp(cursor_position, &buffer_snapshot)
25102                    .is_le(),
25103                "replace_range should start before or at cursor position"
25104            );
25105
25106            let should_replace = match intent {
25107                CompletionIntent::CompleteWithInsert => false,
25108                CompletionIntent::CompleteWithReplace => true,
25109                CompletionIntent::Complete | CompletionIntent::Compose => {
25110                    let insert_mode =
25111                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
25112                            .completions
25113                            .lsp_insert_mode;
25114                    match insert_mode {
25115                        LspInsertMode::Insert => false,
25116                        LspInsertMode::Replace => true,
25117                        LspInsertMode::ReplaceSubsequence => {
25118                            let mut text_to_replace = buffer.chars_for_range(
25119                                buffer.anchor_before(replace_range.start)
25120                                    ..buffer.anchor_after(replace_range.end),
25121                            );
25122                            let mut current_needle = text_to_replace.next();
25123                            for haystack_ch in completion.label.text.chars() {
25124                                if let Some(needle_ch) = current_needle
25125                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
25126                                {
25127                                    current_needle = text_to_replace.next();
25128                                }
25129                            }
25130                            current_needle.is_none()
25131                        }
25132                        LspInsertMode::ReplaceSuffix => {
25133                            if replace_range
25134                                .end
25135                                .cmp(cursor_position, &buffer_snapshot)
25136                                .is_gt()
25137                            {
25138                                let range_after_cursor = *cursor_position..replace_range.end;
25139                                let text_after_cursor = buffer
25140                                    .text_for_range(
25141                                        buffer.anchor_before(range_after_cursor.start)
25142                                            ..buffer.anchor_after(range_after_cursor.end),
25143                                    )
25144                                    .collect::<String>()
25145                                    .to_ascii_lowercase();
25146                                completion
25147                                    .label
25148                                    .text
25149                                    .to_ascii_lowercase()
25150                                    .ends_with(&text_after_cursor)
25151                            } else {
25152                                true
25153                            }
25154                        }
25155                    }
25156                }
25157            };
25158
25159            if should_replace {
25160                replace_range.clone()
25161            } else {
25162                insert_range.clone()
25163            }
25164        } else {
25165            replace_range.clone()
25166        }
25167    };
25168
25169    if range_to_replace
25170        .end
25171        .cmp(cursor_position, &buffer_snapshot)
25172        .is_lt()
25173    {
25174        range_to_replace.end = *cursor_position;
25175    }
25176
25177    let replace_range = range_to_replace.to_offset(buffer);
25178    CompletionEdit {
25179        new_text,
25180        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
25181        snippet,
25182    }
25183}
25184
25185struct CompletionEdit {
25186    new_text: String,
25187    replace_range: Range<BufferOffset>,
25188    snippet: Option<Snippet>,
25189}
25190
25191fn comment_delimiter_for_newline(
25192    start_point: &Point,
25193    buffer: &MultiBufferSnapshot,
25194    language: &LanguageScope,
25195) -> Option<Arc<str>> {
25196    let delimiters = language.line_comment_prefixes();
25197    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
25198    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25199
25200    let num_of_whitespaces = snapshot
25201        .chars_for_range(range.clone())
25202        .take_while(|c| c.is_whitespace())
25203        .count();
25204    let comment_candidate = snapshot
25205        .chars_for_range(range.clone())
25206        .skip(num_of_whitespaces)
25207        .take(max_len_of_delimiter)
25208        .collect::<String>();
25209    let (delimiter, trimmed_len) = delimiters
25210        .iter()
25211        .filter_map(|delimiter| {
25212            let prefix = delimiter.trim_end();
25213            if comment_candidate.starts_with(prefix) {
25214                Some((delimiter, prefix.len()))
25215            } else {
25216                None
25217            }
25218        })
25219        .max_by_key(|(_, len)| *len)?;
25220
25221    if let Some(BlockCommentConfig {
25222        start: block_start, ..
25223    }) = language.block_comment()
25224    {
25225        let block_start_trimmed = block_start.trim_end();
25226        if block_start_trimmed.starts_with(delimiter.trim_end()) {
25227            let line_content = snapshot
25228                .chars_for_range(range)
25229                .skip(num_of_whitespaces)
25230                .take(block_start_trimmed.len())
25231                .collect::<String>();
25232
25233            if line_content.starts_with(block_start_trimmed) {
25234                return None;
25235            }
25236        }
25237    }
25238
25239    let cursor_is_placed_after_comment_marker =
25240        num_of_whitespaces + trimmed_len <= start_point.column as usize;
25241    if cursor_is_placed_after_comment_marker {
25242        Some(delimiter.clone())
25243    } else {
25244        None
25245    }
25246}
25247
25248fn documentation_delimiter_for_newline(
25249    start_point: &Point,
25250    buffer: &MultiBufferSnapshot,
25251    language: &LanguageScope,
25252    newline_config: &mut NewlineConfig,
25253) -> Option<Arc<str>> {
25254    let BlockCommentConfig {
25255        start: start_tag,
25256        end: end_tag,
25257        prefix: delimiter,
25258        tab_size: len,
25259    } = language.documentation_comment()?;
25260    let is_within_block_comment = buffer
25261        .language_scope_at(*start_point)
25262        .is_some_and(|scope| scope.override_name() == Some("comment"));
25263    if !is_within_block_comment {
25264        return None;
25265    }
25266
25267    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25268
25269    let num_of_whitespaces = snapshot
25270        .chars_for_range(range.clone())
25271        .take_while(|c| c.is_whitespace())
25272        .count();
25273
25274    // 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.
25275    let column = start_point.column;
25276    let cursor_is_after_start_tag = {
25277        let start_tag_len = start_tag.len();
25278        let start_tag_line = snapshot
25279            .chars_for_range(range.clone())
25280            .skip(num_of_whitespaces)
25281            .take(start_tag_len)
25282            .collect::<String>();
25283        if start_tag_line.starts_with(start_tag.as_ref()) {
25284            num_of_whitespaces + start_tag_len <= column as usize
25285        } else {
25286            false
25287        }
25288    };
25289
25290    let cursor_is_after_delimiter = {
25291        let delimiter_trim = delimiter.trim_end();
25292        let delimiter_line = snapshot
25293            .chars_for_range(range.clone())
25294            .skip(num_of_whitespaces)
25295            .take(delimiter_trim.len())
25296            .collect::<String>();
25297        if delimiter_line.starts_with(delimiter_trim) {
25298            num_of_whitespaces + delimiter_trim.len() <= column as usize
25299        } else {
25300            false
25301        }
25302    };
25303
25304    let mut needs_extra_line = false;
25305    let mut extra_line_additional_indent = IndentSize::spaces(0);
25306
25307    let cursor_is_before_end_tag_if_exists = {
25308        let mut char_position = 0u32;
25309        let mut end_tag_offset = None;
25310
25311        'outer: for chunk in snapshot.text_for_range(range) {
25312            if let Some(byte_pos) = chunk.find(&**end_tag) {
25313                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
25314                end_tag_offset = Some(char_position + chars_before_match);
25315                break 'outer;
25316            }
25317            char_position += chunk.chars().count() as u32;
25318        }
25319
25320        if let Some(end_tag_offset) = end_tag_offset {
25321            let cursor_is_before_end_tag = column <= end_tag_offset;
25322            if cursor_is_after_start_tag {
25323                if cursor_is_before_end_tag {
25324                    needs_extra_line = true;
25325                }
25326                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
25327                if cursor_is_at_start_of_end_tag {
25328                    extra_line_additional_indent.len = *len;
25329                }
25330            }
25331            cursor_is_before_end_tag
25332        } else {
25333            true
25334        }
25335    };
25336
25337    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
25338        && cursor_is_before_end_tag_if_exists
25339    {
25340        let additional_indent = if cursor_is_after_start_tag {
25341            IndentSize::spaces(*len)
25342        } else {
25343            IndentSize::spaces(0)
25344        };
25345
25346        *newline_config = NewlineConfig::Newline {
25347            additional_indent,
25348            extra_line_additional_indent: if needs_extra_line {
25349                Some(extra_line_additional_indent)
25350            } else {
25351                None
25352            },
25353            prevent_auto_indent: true,
25354        };
25355        Some(delimiter.clone())
25356    } else {
25357        None
25358    }
25359}
25360
25361const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
25362
25363fn list_delimiter_for_newline(
25364    start_point: &Point,
25365    buffer: &MultiBufferSnapshot,
25366    language: &LanguageScope,
25367    newline_config: &mut NewlineConfig,
25368) -> Option<Arc<str>> {
25369    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25370
25371    let num_of_whitespaces = snapshot
25372        .chars_for_range(range.clone())
25373        .take_while(|c| c.is_whitespace())
25374        .count();
25375
25376    let task_list_entries: Vec<_> = language
25377        .task_list()
25378        .into_iter()
25379        .flat_map(|config| {
25380            config
25381                .prefixes
25382                .iter()
25383                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
25384        })
25385        .collect();
25386    let unordered_list_entries: Vec<_> = language
25387        .unordered_list()
25388        .iter()
25389        .map(|marker| (marker.as_ref(), marker.as_ref()))
25390        .collect();
25391
25392    let all_entries: Vec<_> = task_list_entries
25393        .into_iter()
25394        .chain(unordered_list_entries)
25395        .collect();
25396
25397    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
25398        let candidate: String = snapshot
25399            .chars_for_range(range.clone())
25400            .skip(num_of_whitespaces)
25401            .take(max_prefix_len)
25402            .collect();
25403
25404        if let Some((prefix, continuation)) = all_entries
25405            .iter()
25406            .filter(|(prefix, _)| candidate.starts_with(*prefix))
25407            .max_by_key(|(prefix, _)| prefix.len())
25408        {
25409            let end_of_prefix = num_of_whitespaces + prefix.len();
25410            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
25411            let has_content_after_marker = snapshot
25412                .chars_for_range(range)
25413                .skip(end_of_prefix)
25414                .any(|c| !c.is_whitespace());
25415
25416            if has_content_after_marker && cursor_is_after_prefix {
25417                return Some((*continuation).into());
25418            }
25419
25420            if start_point.column as usize == end_of_prefix {
25421                if num_of_whitespaces == 0 {
25422                    *newline_config = NewlineConfig::ClearCurrentLine;
25423                } else {
25424                    *newline_config = NewlineConfig::UnindentCurrentLine {
25425                        continuation: (*continuation).into(),
25426                    };
25427                }
25428            }
25429
25430            return None;
25431        }
25432    }
25433
25434    let candidate: String = snapshot
25435        .chars_for_range(range.clone())
25436        .skip(num_of_whitespaces)
25437        .take(ORDERED_LIST_MAX_MARKER_LEN)
25438        .collect();
25439
25440    for ordered_config in language.ordered_list() {
25441        let regex = match Regex::new(&ordered_config.pattern) {
25442            Ok(r) => r,
25443            Err(_) => continue,
25444        };
25445
25446        if let Some(captures) = regex.captures(&candidate) {
25447            let full_match = captures.get(0)?;
25448            let marker_len = full_match.len();
25449            let end_of_prefix = num_of_whitespaces + marker_len;
25450            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
25451
25452            let has_content_after_marker = snapshot
25453                .chars_for_range(range)
25454                .skip(end_of_prefix)
25455                .any(|c| !c.is_whitespace());
25456
25457            if has_content_after_marker && cursor_is_after_prefix {
25458                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
25459                let continuation = ordered_config
25460                    .format
25461                    .replace("{1}", &(number + 1).to_string());
25462                return Some(continuation.into());
25463            }
25464
25465            if start_point.column as usize == end_of_prefix {
25466                let continuation = ordered_config.format.replace("{1}", "1");
25467                if num_of_whitespaces == 0 {
25468                    *newline_config = NewlineConfig::ClearCurrentLine;
25469                } else {
25470                    *newline_config = NewlineConfig::UnindentCurrentLine {
25471                        continuation: continuation.into(),
25472                    };
25473                }
25474            }
25475
25476            return None;
25477        }
25478    }
25479
25480    None
25481}
25482
25483fn is_list_prefix_row(
25484    row: MultiBufferRow,
25485    buffer: &MultiBufferSnapshot,
25486    language: &LanguageScope,
25487) -> bool {
25488    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
25489        return false;
25490    };
25491
25492    let num_of_whitespaces = snapshot
25493        .chars_for_range(range.clone())
25494        .take_while(|c| c.is_whitespace())
25495        .count();
25496
25497    let task_list_prefixes: Vec<_> = language
25498        .task_list()
25499        .into_iter()
25500        .flat_map(|config| {
25501            config
25502                .prefixes
25503                .iter()
25504                .map(|p| p.as_ref())
25505                .collect::<Vec<_>>()
25506        })
25507        .collect();
25508    let unordered_list_markers: Vec<_> = language
25509        .unordered_list()
25510        .iter()
25511        .map(|marker| marker.as_ref())
25512        .collect();
25513    let all_prefixes: Vec<_> = task_list_prefixes
25514        .into_iter()
25515        .chain(unordered_list_markers)
25516        .collect();
25517    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
25518        let candidate: String = snapshot
25519            .chars_for_range(range.clone())
25520            .skip(num_of_whitespaces)
25521            .take(max_prefix_len)
25522            .collect();
25523        if all_prefixes
25524            .iter()
25525            .any(|prefix| candidate.starts_with(*prefix))
25526        {
25527            return true;
25528        }
25529    }
25530
25531    let ordered_list_candidate: String = snapshot
25532        .chars_for_range(range)
25533        .skip(num_of_whitespaces)
25534        .take(ORDERED_LIST_MAX_MARKER_LEN)
25535        .collect();
25536    for ordered_config in language.ordered_list() {
25537        let regex = match Regex::new(&ordered_config.pattern) {
25538            Ok(r) => r,
25539            Err(_) => continue,
25540        };
25541        if let Some(captures) = regex.captures(&ordered_list_candidate) {
25542            return captures.get(0).is_some();
25543        }
25544    }
25545
25546    false
25547}
25548
25549#[derive(Debug)]
25550enum NewlineConfig {
25551    /// Insert newline with optional additional indent and optional extra blank line
25552    Newline {
25553        additional_indent: IndentSize,
25554        extra_line_additional_indent: Option<IndentSize>,
25555        prevent_auto_indent: bool,
25556    },
25557    /// Clear the current line
25558    ClearCurrentLine,
25559    /// Unindent the current line and add continuation
25560    UnindentCurrentLine { continuation: Arc<str> },
25561}
25562
25563impl NewlineConfig {
25564    fn has_extra_line(&self) -> bool {
25565        matches!(
25566            self,
25567            Self::Newline {
25568                extra_line_additional_indent: Some(_),
25569                ..
25570            }
25571        )
25572    }
25573
25574    fn insert_extra_newline_brackets(
25575        buffer: &MultiBufferSnapshot,
25576        range: Range<MultiBufferOffset>,
25577        language: &language::LanguageScope,
25578    ) -> bool {
25579        let leading_whitespace_len = buffer
25580            .reversed_chars_at(range.start)
25581            .take_while(|c| c.is_whitespace() && *c != '\n')
25582            .map(|c| c.len_utf8())
25583            .sum::<usize>();
25584        let trailing_whitespace_len = buffer
25585            .chars_at(range.end)
25586            .take_while(|c| c.is_whitespace() && *c != '\n')
25587            .map(|c| c.len_utf8())
25588            .sum::<usize>();
25589        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
25590
25591        language.brackets().any(|(pair, enabled)| {
25592            let pair_start = pair.start.trim_end();
25593            let pair_end = pair.end.trim_start();
25594
25595            enabled
25596                && pair.newline
25597                && buffer.contains_str_at(range.end, pair_end)
25598                && buffer.contains_str_at(
25599                    range.start.saturating_sub_usize(pair_start.len()),
25600                    pair_start,
25601                )
25602        })
25603    }
25604
25605    fn insert_extra_newline_tree_sitter(
25606        buffer: &MultiBufferSnapshot,
25607        range: Range<MultiBufferOffset>,
25608    ) -> bool {
25609        let (buffer, range) = match buffer
25610            .range_to_buffer_ranges(range.start..=range.end)
25611            .as_slice()
25612        {
25613            [(buffer, range, _)] => (*buffer, range.clone()),
25614            _ => return false,
25615        };
25616        let pair = {
25617            let mut result: Option<BracketMatch<usize>> = None;
25618
25619            for pair in buffer
25620                .all_bracket_ranges(range.start.0..range.end.0)
25621                .filter(move |pair| {
25622                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
25623                })
25624            {
25625                let len = pair.close_range.end - pair.open_range.start;
25626
25627                if let Some(existing) = &result {
25628                    let existing_len = existing.close_range.end - existing.open_range.start;
25629                    if len > existing_len {
25630                        continue;
25631                    }
25632                }
25633
25634                result = Some(pair);
25635            }
25636
25637            result
25638        };
25639        let Some(pair) = pair else {
25640            return false;
25641        };
25642        pair.newline_only
25643            && buffer
25644                .chars_for_range(pair.open_range.end..range.start.0)
25645                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
25646                .all(|c| c.is_whitespace() && c != '\n')
25647    }
25648}
25649
25650fn update_uncommitted_diff_for_buffer(
25651    editor: Entity<Editor>,
25652    project: &Entity<Project>,
25653    buffers: impl IntoIterator<Item = Entity<Buffer>>,
25654    buffer: Entity<MultiBuffer>,
25655    cx: &mut App,
25656) -> Task<()> {
25657    let mut tasks = Vec::new();
25658    project.update(cx, |project, cx| {
25659        for buffer in buffers {
25660            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
25661                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
25662            }
25663        }
25664    });
25665    cx.spawn(async move |cx| {
25666        let diffs = future::join_all(tasks).await;
25667        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
25668            return;
25669        }
25670
25671        buffer.update(cx, |buffer, cx| {
25672            for diff in diffs.into_iter().flatten() {
25673                buffer.add_diff(diff, cx);
25674            }
25675        });
25676    })
25677}
25678
25679fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
25680    let tab_size = tab_size.get() as usize;
25681    let mut width = offset;
25682
25683    for ch in text.chars() {
25684        width += if ch == '\t' {
25685            tab_size - (width % tab_size)
25686        } else {
25687            1
25688        };
25689    }
25690
25691    width - offset
25692}
25693
25694#[cfg(test)]
25695mod tests {
25696    use super::*;
25697
25698    #[test]
25699    fn test_string_size_with_expanded_tabs() {
25700        let nz = |val| NonZeroU32::new(val).unwrap();
25701        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
25702        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
25703        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
25704        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
25705        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
25706        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
25707        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
25708        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
25709    }
25710}
25711
25712/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
25713struct WordBreakingTokenizer<'a> {
25714    input: &'a str,
25715}
25716
25717impl<'a> WordBreakingTokenizer<'a> {
25718    fn new(input: &'a str) -> Self {
25719        Self { input }
25720    }
25721}
25722
25723fn is_char_ideographic(ch: char) -> bool {
25724    use unicode_script::Script::*;
25725    use unicode_script::UnicodeScript;
25726    matches!(ch.script(), Han | Tangut | Yi)
25727}
25728
25729fn is_grapheme_ideographic(text: &str) -> bool {
25730    text.chars().any(is_char_ideographic)
25731}
25732
25733fn is_grapheme_whitespace(text: &str) -> bool {
25734    text.chars().any(|x| x.is_whitespace())
25735}
25736
25737fn should_stay_with_preceding_ideograph(text: &str) -> bool {
25738    text.chars()
25739        .next()
25740        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
25741}
25742
25743#[derive(PartialEq, Eq, Debug, Clone, Copy)]
25744enum WordBreakToken<'a> {
25745    Word { token: &'a str, grapheme_len: usize },
25746    InlineWhitespace { token: &'a str, grapheme_len: usize },
25747    Newline,
25748}
25749
25750impl<'a> Iterator for WordBreakingTokenizer<'a> {
25751    /// Yields a span, the count of graphemes in the token, and whether it was
25752    /// whitespace. Note that it also breaks at word boundaries.
25753    type Item = WordBreakToken<'a>;
25754
25755    fn next(&mut self) -> Option<Self::Item> {
25756        use unicode_segmentation::UnicodeSegmentation;
25757        if self.input.is_empty() {
25758            return None;
25759        }
25760
25761        let mut iter = self.input.graphemes(true).peekable();
25762        let mut offset = 0;
25763        let mut grapheme_len = 0;
25764        if let Some(first_grapheme) = iter.next() {
25765            let is_newline = first_grapheme == "\n";
25766            let is_whitespace = is_grapheme_whitespace(first_grapheme);
25767            offset += first_grapheme.len();
25768            grapheme_len += 1;
25769            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
25770                if let Some(grapheme) = iter.peek().copied()
25771                    && should_stay_with_preceding_ideograph(grapheme)
25772                {
25773                    offset += grapheme.len();
25774                    grapheme_len += 1;
25775                }
25776            } else {
25777                let mut words = self.input[offset..].split_word_bound_indices().peekable();
25778                let mut next_word_bound = words.peek().copied();
25779                if next_word_bound.is_some_and(|(i, _)| i == 0) {
25780                    next_word_bound = words.next();
25781                }
25782                while let Some(grapheme) = iter.peek().copied() {
25783                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
25784                        break;
25785                    };
25786                    if is_grapheme_whitespace(grapheme) != is_whitespace
25787                        || (grapheme == "\n") != is_newline
25788                    {
25789                        break;
25790                    };
25791                    offset += grapheme.len();
25792                    grapheme_len += 1;
25793                    iter.next();
25794                }
25795            }
25796            let token = &self.input[..offset];
25797            self.input = &self.input[offset..];
25798            if token == "\n" {
25799                Some(WordBreakToken::Newline)
25800            } else if is_whitespace {
25801                Some(WordBreakToken::InlineWhitespace {
25802                    token,
25803                    grapheme_len,
25804                })
25805            } else {
25806                Some(WordBreakToken::Word {
25807                    token,
25808                    grapheme_len,
25809                })
25810            }
25811        } else {
25812            None
25813        }
25814    }
25815}
25816
25817#[test]
25818fn test_word_breaking_tokenizer() {
25819    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
25820        ("", &[]),
25821        ("  ", &[whitespace("  ", 2)]),
25822        ("Ʒ", &[word("Ʒ", 1)]),
25823        ("Ǽ", &[word("Ǽ", 1)]),
25824        ("", &[word("", 1)]),
25825        ("⋑⋑", &[word("⋑⋑", 2)]),
25826        (
25827            "原理,进而",
25828            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
25829        ),
25830        (
25831            "hello world",
25832            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
25833        ),
25834        (
25835            "hello, world",
25836            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
25837        ),
25838        (
25839            "  hello world",
25840            &[
25841                whitespace("  ", 2),
25842                word("hello", 5),
25843                whitespace(" ", 1),
25844                word("world", 5),
25845            ],
25846        ),
25847        (
25848            "这是什么 \n 钢笔",
25849            &[
25850                word("", 1),
25851                word("", 1),
25852                word("", 1),
25853                word("", 1),
25854                whitespace(" ", 1),
25855                newline(),
25856                whitespace(" ", 1),
25857                word("", 1),
25858                word("", 1),
25859            ],
25860        ),
25861        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
25862    ];
25863
25864    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
25865        WordBreakToken::Word {
25866            token,
25867            grapheme_len,
25868        }
25869    }
25870
25871    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
25872        WordBreakToken::InlineWhitespace {
25873            token,
25874            grapheme_len,
25875        }
25876    }
25877
25878    fn newline() -> WordBreakToken<'static> {
25879        WordBreakToken::Newline
25880    }
25881
25882    for (input, result) in tests {
25883        assert_eq!(
25884            WordBreakingTokenizer::new(input)
25885                .collect::<Vec<_>>()
25886                .as_slice(),
25887            *result,
25888        );
25889    }
25890}
25891
25892fn wrap_with_prefix(
25893    first_line_prefix: String,
25894    subsequent_lines_prefix: String,
25895    unwrapped_text: String,
25896    wrap_column: usize,
25897    tab_size: NonZeroU32,
25898    preserve_existing_whitespace: bool,
25899) -> String {
25900    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
25901    let subsequent_lines_prefix_len =
25902        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
25903    let mut wrapped_text = String::new();
25904    let mut current_line = first_line_prefix;
25905    let mut is_first_line = true;
25906
25907    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
25908    let mut current_line_len = first_line_prefix_len;
25909    let mut in_whitespace = false;
25910    for token in tokenizer {
25911        let have_preceding_whitespace = in_whitespace;
25912        match token {
25913            WordBreakToken::Word {
25914                token,
25915                grapheme_len,
25916            } => {
25917                in_whitespace = false;
25918                let current_prefix_len = if is_first_line {
25919                    first_line_prefix_len
25920                } else {
25921                    subsequent_lines_prefix_len
25922                };
25923                if current_line_len + grapheme_len > wrap_column
25924                    && current_line_len != current_prefix_len
25925                {
25926                    wrapped_text.push_str(current_line.trim_end());
25927                    wrapped_text.push('\n');
25928                    is_first_line = false;
25929                    current_line = subsequent_lines_prefix.clone();
25930                    current_line_len = subsequent_lines_prefix_len;
25931                }
25932                current_line.push_str(token);
25933                current_line_len += grapheme_len;
25934            }
25935            WordBreakToken::InlineWhitespace {
25936                mut token,
25937                mut grapheme_len,
25938            } => {
25939                in_whitespace = true;
25940                if have_preceding_whitespace && !preserve_existing_whitespace {
25941                    continue;
25942                }
25943                if !preserve_existing_whitespace {
25944                    // Keep a single whitespace grapheme as-is
25945                    if let Some(first) =
25946                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
25947                    {
25948                        token = first;
25949                    } else {
25950                        token = " ";
25951                    }
25952                    grapheme_len = 1;
25953                }
25954                let current_prefix_len = if is_first_line {
25955                    first_line_prefix_len
25956                } else {
25957                    subsequent_lines_prefix_len
25958                };
25959                if current_line_len + grapheme_len > wrap_column {
25960                    wrapped_text.push_str(current_line.trim_end());
25961                    wrapped_text.push('\n');
25962                    is_first_line = false;
25963                    current_line = subsequent_lines_prefix.clone();
25964                    current_line_len = subsequent_lines_prefix_len;
25965                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
25966                    current_line.push_str(token);
25967                    current_line_len += grapheme_len;
25968                }
25969            }
25970            WordBreakToken::Newline => {
25971                in_whitespace = true;
25972                let current_prefix_len = if is_first_line {
25973                    first_line_prefix_len
25974                } else {
25975                    subsequent_lines_prefix_len
25976                };
25977                if preserve_existing_whitespace {
25978                    wrapped_text.push_str(current_line.trim_end());
25979                    wrapped_text.push('\n');
25980                    is_first_line = false;
25981                    current_line = subsequent_lines_prefix.clone();
25982                    current_line_len = subsequent_lines_prefix_len;
25983                } else if have_preceding_whitespace {
25984                    continue;
25985                } else if current_line_len + 1 > wrap_column
25986                    && current_line_len != current_prefix_len
25987                {
25988                    wrapped_text.push_str(current_line.trim_end());
25989                    wrapped_text.push('\n');
25990                    is_first_line = false;
25991                    current_line = subsequent_lines_prefix.clone();
25992                    current_line_len = subsequent_lines_prefix_len;
25993                } else if current_line_len != current_prefix_len {
25994                    current_line.push(' ');
25995                    current_line_len += 1;
25996                }
25997            }
25998        }
25999    }
26000
26001    if !current_line.is_empty() {
26002        wrapped_text.push_str(&current_line);
26003    }
26004    wrapped_text
26005}
26006
26007#[test]
26008fn test_wrap_with_prefix() {
26009    assert_eq!(
26010        wrap_with_prefix(
26011            "# ".to_string(),
26012            "# ".to_string(),
26013            "abcdefg".to_string(),
26014            4,
26015            NonZeroU32::new(4).unwrap(),
26016            false,
26017        ),
26018        "# abcdefg"
26019    );
26020    assert_eq!(
26021        wrap_with_prefix(
26022            "".to_string(),
26023            "".to_string(),
26024            "\thello world".to_string(),
26025            8,
26026            NonZeroU32::new(4).unwrap(),
26027            false,
26028        ),
26029        "hello\nworld"
26030    );
26031    assert_eq!(
26032        wrap_with_prefix(
26033            "// ".to_string(),
26034            "// ".to_string(),
26035            "xx \nyy zz aa bb cc".to_string(),
26036            12,
26037            NonZeroU32::new(4).unwrap(),
26038            false,
26039        ),
26040        "// xx yy zz\n// aa bb cc"
26041    );
26042    assert_eq!(
26043        wrap_with_prefix(
26044            String::new(),
26045            String::new(),
26046            "这是什么 \n 钢笔".to_string(),
26047            3,
26048            NonZeroU32::new(4).unwrap(),
26049            false,
26050        ),
26051        "这是什\n么 钢\n"
26052    );
26053    assert_eq!(
26054        wrap_with_prefix(
26055            String::new(),
26056            String::new(),
26057            format!("foo{}bar", '\u{2009}'), // thin space
26058            80,
26059            NonZeroU32::new(4).unwrap(),
26060            false,
26061        ),
26062        format!("foo{}bar", '\u{2009}')
26063    );
26064}
26065
26066pub trait CollaborationHub {
26067    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
26068    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
26069    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
26070}
26071
26072impl CollaborationHub for Entity<Project> {
26073    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
26074        self.read(cx).collaborators()
26075    }
26076
26077    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
26078        self.read(cx).user_store().read(cx).participant_indices()
26079    }
26080
26081    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
26082        let this = self.read(cx);
26083        let user_ids = this.collaborators().values().map(|c| c.user_id);
26084        this.user_store().read(cx).participant_names(user_ids, cx)
26085    }
26086}
26087
26088pub trait SemanticsProvider {
26089    fn hover(
26090        &self,
26091        buffer: &Entity<Buffer>,
26092        position: text::Anchor,
26093        cx: &mut App,
26094    ) -> Option<Task<Option<Vec<project::Hover>>>>;
26095
26096    fn inline_values(
26097        &self,
26098        buffer_handle: Entity<Buffer>,
26099        range: Range<text::Anchor>,
26100        cx: &mut App,
26101    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
26102
26103    fn applicable_inlay_chunks(
26104        &self,
26105        buffer: &Entity<Buffer>,
26106        ranges: &[Range<text::Anchor>],
26107        cx: &mut App,
26108    ) -> Vec<Range<BufferRow>>;
26109
26110    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
26111
26112    fn inlay_hints(
26113        &self,
26114        invalidate: InvalidationStrategy,
26115        buffer: Entity<Buffer>,
26116        ranges: Vec<Range<text::Anchor>>,
26117        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
26118        cx: &mut App,
26119    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
26120
26121    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
26122
26123    fn document_highlights(
26124        &self,
26125        buffer: &Entity<Buffer>,
26126        position: text::Anchor,
26127        cx: &mut App,
26128    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
26129
26130    fn definitions(
26131        &self,
26132        buffer: &Entity<Buffer>,
26133        position: text::Anchor,
26134        kind: GotoDefinitionKind,
26135        cx: &mut App,
26136    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
26137
26138    fn range_for_rename(
26139        &self,
26140        buffer: &Entity<Buffer>,
26141        position: text::Anchor,
26142        cx: &mut App,
26143    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
26144
26145    fn perform_rename(
26146        &self,
26147        buffer: &Entity<Buffer>,
26148        position: text::Anchor,
26149        new_name: String,
26150        cx: &mut App,
26151    ) -> Option<Task<Result<ProjectTransaction>>>;
26152}
26153
26154pub trait CompletionProvider {
26155    fn completions(
26156        &self,
26157        excerpt_id: ExcerptId,
26158        buffer: &Entity<Buffer>,
26159        buffer_position: text::Anchor,
26160        trigger: CompletionContext,
26161        window: &mut Window,
26162        cx: &mut Context<Editor>,
26163    ) -> Task<Result<Vec<CompletionResponse>>>;
26164
26165    fn resolve_completions(
26166        &self,
26167        _buffer: Entity<Buffer>,
26168        _completion_indices: Vec<usize>,
26169        _completions: Rc<RefCell<Box<[Completion]>>>,
26170        _cx: &mut Context<Editor>,
26171    ) -> Task<Result<bool>> {
26172        Task::ready(Ok(false))
26173    }
26174
26175    fn apply_additional_edits_for_completion(
26176        &self,
26177        _buffer: Entity<Buffer>,
26178        _completions: Rc<RefCell<Box<[Completion]>>>,
26179        _completion_index: usize,
26180        _push_to_history: bool,
26181        _cx: &mut Context<Editor>,
26182    ) -> Task<Result<Option<language::Transaction>>> {
26183        Task::ready(Ok(None))
26184    }
26185
26186    fn is_completion_trigger(
26187        &self,
26188        buffer: &Entity<Buffer>,
26189        position: language::Anchor,
26190        text: &str,
26191        trigger_in_words: bool,
26192        cx: &mut Context<Editor>,
26193    ) -> bool;
26194
26195    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
26196
26197    fn sort_completions(&self) -> bool {
26198        true
26199    }
26200
26201    fn filter_completions(&self) -> bool {
26202        true
26203    }
26204
26205    fn show_snippets(&self) -> bool {
26206        false
26207    }
26208}
26209
26210pub trait CodeActionProvider {
26211    fn id(&self) -> Arc<str>;
26212
26213    fn code_actions(
26214        &self,
26215        buffer: &Entity<Buffer>,
26216        range: Range<text::Anchor>,
26217        window: &mut Window,
26218        cx: &mut App,
26219    ) -> Task<Result<Vec<CodeAction>>>;
26220
26221    fn apply_code_action(
26222        &self,
26223        buffer_handle: Entity<Buffer>,
26224        action: CodeAction,
26225        excerpt_id: ExcerptId,
26226        push_to_history: bool,
26227        window: &mut Window,
26228        cx: &mut App,
26229    ) -> Task<Result<ProjectTransaction>>;
26230}
26231
26232impl CodeActionProvider for Entity<Project> {
26233    fn id(&self) -> Arc<str> {
26234        "project".into()
26235    }
26236
26237    fn code_actions(
26238        &self,
26239        buffer: &Entity<Buffer>,
26240        range: Range<text::Anchor>,
26241        _window: &mut Window,
26242        cx: &mut App,
26243    ) -> Task<Result<Vec<CodeAction>>> {
26244        self.update(cx, |project, cx| {
26245            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
26246            let code_actions = project.code_actions(buffer, range, None, cx);
26247            cx.background_spawn(async move {
26248                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
26249                Ok(code_lens_actions
26250                    .context("code lens fetch")?
26251                    .into_iter()
26252                    .flatten()
26253                    .chain(
26254                        code_actions
26255                            .context("code action fetch")?
26256                            .into_iter()
26257                            .flatten(),
26258                    )
26259                    .collect())
26260            })
26261        })
26262    }
26263
26264    fn apply_code_action(
26265        &self,
26266        buffer_handle: Entity<Buffer>,
26267        action: CodeAction,
26268        _excerpt_id: ExcerptId,
26269        push_to_history: bool,
26270        _window: &mut Window,
26271        cx: &mut App,
26272    ) -> Task<Result<ProjectTransaction>> {
26273        self.update(cx, |project, cx| {
26274            project.apply_code_action(buffer_handle, action, push_to_history, cx)
26275        })
26276    }
26277}
26278
26279fn snippet_completions(
26280    project: &Project,
26281    buffer: &Entity<Buffer>,
26282    buffer_anchor: text::Anchor,
26283    classifier: CharClassifier,
26284    cx: &mut App,
26285) -> Task<Result<CompletionResponse>> {
26286    let languages = buffer.read(cx).languages_at(buffer_anchor);
26287    let snippet_store = project.snippets().read(cx);
26288
26289    let scopes: Vec<_> = languages
26290        .iter()
26291        .filter_map(|language| {
26292            let language_name = language.lsp_id();
26293            let snippets = snippet_store.snippets_for(Some(language_name), cx);
26294
26295            if snippets.is_empty() {
26296                None
26297            } else {
26298                Some((language.default_scope(), snippets))
26299            }
26300        })
26301        .collect();
26302
26303    if scopes.is_empty() {
26304        return Task::ready(Ok(CompletionResponse {
26305            completions: vec![],
26306            display_options: CompletionDisplayOptions::default(),
26307            is_incomplete: false,
26308        }));
26309    }
26310
26311    let snapshot = buffer.read(cx).text_snapshot();
26312    let executor = cx.background_executor().clone();
26313
26314    cx.background_spawn(async move {
26315        let is_word_char = |c| classifier.is_word(c);
26316
26317        let mut is_incomplete = false;
26318        let mut completions: Vec<Completion> = Vec::new();
26319
26320        const MAX_PREFIX_LEN: usize = 128;
26321        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
26322        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
26323        let window_start = snapshot.clip_offset(window_start, Bias::Left);
26324
26325        let max_buffer_window: String = snapshot
26326            .text_for_range(window_start..buffer_offset)
26327            .collect();
26328
26329        if max_buffer_window.is_empty() {
26330            return Ok(CompletionResponse {
26331                completions: vec![],
26332                display_options: CompletionDisplayOptions::default(),
26333                is_incomplete: true,
26334            });
26335        }
26336
26337        for (_scope, snippets) in scopes.into_iter() {
26338            // Sort snippets by word count to match longer snippet prefixes first.
26339            let mut sorted_snippet_candidates = snippets
26340                .iter()
26341                .enumerate()
26342                .flat_map(|(snippet_ix, snippet)| {
26343                    snippet
26344                        .prefix
26345                        .iter()
26346                        .enumerate()
26347                        .map(move |(prefix_ix, prefix)| {
26348                            let word_count =
26349                                snippet_candidate_suffixes(prefix, is_word_char).count();
26350                            ((snippet_ix, prefix_ix), prefix, word_count)
26351                        })
26352                })
26353                .collect_vec();
26354            sorted_snippet_candidates
26355                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
26356
26357            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
26358
26359            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
26360                .take(
26361                    sorted_snippet_candidates
26362                        .first()
26363                        .map(|(_, _, word_count)| *word_count)
26364                        .unwrap_or_default(),
26365                )
26366                .collect_vec();
26367
26368            const MAX_RESULTS: usize = 100;
26369            // Each match also remembers how many characters from the buffer it consumed
26370            let mut matches: Vec<(StringMatch, usize)> = vec![];
26371
26372            let mut snippet_list_cutoff_index = 0;
26373            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
26374                let word_count = buffer_index + 1;
26375                // Increase `snippet_list_cutoff_index` until we have all of the
26376                // snippets with sufficiently many words.
26377                while sorted_snippet_candidates
26378                    .get(snippet_list_cutoff_index)
26379                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
26380                        *snippet_word_count >= word_count
26381                    })
26382                {
26383                    snippet_list_cutoff_index += 1;
26384                }
26385
26386                // Take only the candidates with at least `word_count` many words
26387                let snippet_candidates_at_word_len =
26388                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
26389
26390                let candidates = snippet_candidates_at_word_len
26391                    .iter()
26392                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
26393                    .enumerate() // index in `sorted_snippet_candidates`
26394                    // First char must match
26395                    .filter(|(_ix, prefix)| {
26396                        itertools::equal(
26397                            prefix
26398                                .chars()
26399                                .next()
26400                                .into_iter()
26401                                .flat_map(|c| c.to_lowercase()),
26402                            buffer_window
26403                                .chars()
26404                                .next()
26405                                .into_iter()
26406                                .flat_map(|c| c.to_lowercase()),
26407                        )
26408                    })
26409                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
26410                    .collect::<Vec<StringMatchCandidate>>();
26411
26412                matches.extend(
26413                    fuzzy::match_strings(
26414                        &candidates,
26415                        &buffer_window,
26416                        buffer_window.chars().any(|c| c.is_uppercase()),
26417                        true,
26418                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
26419                        &Default::default(),
26420                        executor.clone(),
26421                    )
26422                    .await
26423                    .into_iter()
26424                    .map(|string_match| (string_match, buffer_window.len())),
26425                );
26426
26427                if matches.len() >= MAX_RESULTS {
26428                    break;
26429                }
26430            }
26431
26432            let to_lsp = |point: &text::Anchor| {
26433                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
26434                point_to_lsp(end)
26435            };
26436            let lsp_end = to_lsp(&buffer_anchor);
26437
26438            if matches.len() >= MAX_RESULTS {
26439                is_incomplete = true;
26440            }
26441
26442            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
26443                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
26444                    sorted_snippet_candidates[string_match.candidate_id];
26445                let snippet = &snippets[snippet_index];
26446                let start = buffer_offset - buffer_window_len;
26447                let start = snapshot.anchor_before(start);
26448                let range = start..buffer_anchor;
26449                let lsp_start = to_lsp(&start);
26450                let lsp_range = lsp::Range {
26451                    start: lsp_start,
26452                    end: lsp_end,
26453                };
26454                Completion {
26455                    replace_range: range,
26456                    new_text: snippet.body.clone(),
26457                    source: CompletionSource::Lsp {
26458                        insert_range: None,
26459                        server_id: LanguageServerId(usize::MAX),
26460                        resolved: true,
26461                        lsp_completion: Box::new(lsp::CompletionItem {
26462                            label: snippet.prefix.first().unwrap().clone(),
26463                            kind: Some(CompletionItemKind::SNIPPET),
26464                            label_details: snippet.description.as_ref().map(|description| {
26465                                lsp::CompletionItemLabelDetails {
26466                                    detail: Some(description.clone()),
26467                                    description: None,
26468                                }
26469                            }),
26470                            insert_text_format: Some(InsertTextFormat::SNIPPET),
26471                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
26472                                lsp::InsertReplaceEdit {
26473                                    new_text: snippet.body.clone(),
26474                                    insert: lsp_range,
26475                                    replace: lsp_range,
26476                                },
26477                            )),
26478                            filter_text: Some(snippet.body.clone()),
26479                            sort_text: Some(char::MAX.to_string()),
26480                            ..lsp::CompletionItem::default()
26481                        }),
26482                        lsp_defaults: None,
26483                    },
26484                    label: CodeLabel {
26485                        text: matching_prefix.clone(),
26486                        runs: Vec::new(),
26487                        filter_range: 0..matching_prefix.len(),
26488                    },
26489                    icon_path: None,
26490                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
26491                        single_line: snippet.name.clone().into(),
26492                        plain_text: snippet
26493                            .description
26494                            .clone()
26495                            .map(|description| description.into()),
26496                    }),
26497                    insert_text_mode: None,
26498                    confirm: None,
26499                    match_start: Some(start),
26500                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
26501                }
26502            }));
26503        }
26504
26505        Ok(CompletionResponse {
26506            completions,
26507            display_options: CompletionDisplayOptions::default(),
26508            is_incomplete,
26509        })
26510    })
26511}
26512
26513impl CompletionProvider for Entity<Project> {
26514    fn completions(
26515        &self,
26516        _excerpt_id: ExcerptId,
26517        buffer: &Entity<Buffer>,
26518        buffer_position: text::Anchor,
26519        options: CompletionContext,
26520        _window: &mut Window,
26521        cx: &mut Context<Editor>,
26522    ) -> Task<Result<Vec<CompletionResponse>>> {
26523        self.update(cx, |project, cx| {
26524            let task = project.completions(buffer, buffer_position, options, cx);
26525            cx.background_spawn(task)
26526        })
26527    }
26528
26529    fn resolve_completions(
26530        &self,
26531        buffer: Entity<Buffer>,
26532        completion_indices: Vec<usize>,
26533        completions: Rc<RefCell<Box<[Completion]>>>,
26534        cx: &mut Context<Editor>,
26535    ) -> Task<Result<bool>> {
26536        self.update(cx, |project, cx| {
26537            project.lsp_store().update(cx, |lsp_store, cx| {
26538                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
26539            })
26540        })
26541    }
26542
26543    fn apply_additional_edits_for_completion(
26544        &self,
26545        buffer: Entity<Buffer>,
26546        completions: Rc<RefCell<Box<[Completion]>>>,
26547        completion_index: usize,
26548        push_to_history: bool,
26549        cx: &mut Context<Editor>,
26550    ) -> Task<Result<Option<language::Transaction>>> {
26551        self.update(cx, |project, cx| {
26552            project.lsp_store().update(cx, |lsp_store, cx| {
26553                lsp_store.apply_additional_edits_for_completion(
26554                    buffer,
26555                    completions,
26556                    completion_index,
26557                    push_to_history,
26558                    cx,
26559                )
26560            })
26561        })
26562    }
26563
26564    fn is_completion_trigger(
26565        &self,
26566        buffer: &Entity<Buffer>,
26567        position: language::Anchor,
26568        text: &str,
26569        trigger_in_words: bool,
26570        cx: &mut Context<Editor>,
26571    ) -> bool {
26572        let mut chars = text.chars();
26573        let char = if let Some(char) = chars.next() {
26574            char
26575        } else {
26576            return false;
26577        };
26578        if chars.next().is_some() {
26579            return false;
26580        }
26581
26582        let buffer = buffer.read(cx);
26583        let snapshot = buffer.snapshot();
26584        let classifier = snapshot
26585            .char_classifier_at(position)
26586            .scope_context(Some(CharScopeContext::Completion));
26587        if trigger_in_words && classifier.is_word(char) {
26588            return true;
26589        }
26590
26591        buffer.completion_triggers().contains(text)
26592    }
26593
26594    fn show_snippets(&self) -> bool {
26595        true
26596    }
26597}
26598
26599impl SemanticsProvider for Entity<Project> {
26600    fn hover(
26601        &self,
26602        buffer: &Entity<Buffer>,
26603        position: text::Anchor,
26604        cx: &mut App,
26605    ) -> Option<Task<Option<Vec<project::Hover>>>> {
26606        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
26607    }
26608
26609    fn document_highlights(
26610        &self,
26611        buffer: &Entity<Buffer>,
26612        position: text::Anchor,
26613        cx: &mut App,
26614    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
26615        Some(self.update(cx, |project, cx| {
26616            project.document_highlights(buffer, position, cx)
26617        }))
26618    }
26619
26620    fn definitions(
26621        &self,
26622        buffer: &Entity<Buffer>,
26623        position: text::Anchor,
26624        kind: GotoDefinitionKind,
26625        cx: &mut App,
26626    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
26627        Some(self.update(cx, |project, cx| match kind {
26628            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
26629            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
26630            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
26631            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
26632        }))
26633    }
26634
26635    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
26636        self.update(cx, |project, cx| {
26637            if project
26638                .active_debug_session(cx)
26639                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
26640            {
26641                return true;
26642            }
26643
26644            buffer.update(cx, |buffer, cx| {
26645                project.any_language_server_supports_inlay_hints(buffer, cx)
26646            })
26647        })
26648    }
26649
26650    fn inline_values(
26651        &self,
26652        buffer_handle: Entity<Buffer>,
26653        range: Range<text::Anchor>,
26654        cx: &mut App,
26655    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
26656        self.update(cx, |project, cx| {
26657            let (session, active_stack_frame) = project.active_debug_session(cx)?;
26658
26659            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
26660        })
26661    }
26662
26663    fn applicable_inlay_chunks(
26664        &self,
26665        buffer: &Entity<Buffer>,
26666        ranges: &[Range<text::Anchor>],
26667        cx: &mut App,
26668    ) -> Vec<Range<BufferRow>> {
26669        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
26670            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
26671        })
26672    }
26673
26674    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
26675        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
26676            lsp_store.invalidate_inlay_hints(for_buffers)
26677        });
26678    }
26679
26680    fn inlay_hints(
26681        &self,
26682        invalidate: InvalidationStrategy,
26683        buffer: Entity<Buffer>,
26684        ranges: Vec<Range<text::Anchor>>,
26685        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
26686        cx: &mut App,
26687    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
26688        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
26689            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
26690        }))
26691    }
26692
26693    fn range_for_rename(
26694        &self,
26695        buffer: &Entity<Buffer>,
26696        position: text::Anchor,
26697        cx: &mut App,
26698    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
26699        Some(self.update(cx, |project, cx| {
26700            let buffer = buffer.clone();
26701            let task = project.prepare_rename(buffer.clone(), position, cx);
26702            cx.spawn(async move |_, cx| {
26703                Ok(match task.await? {
26704                    PrepareRenameResponse::Success(range) => Some(range),
26705                    PrepareRenameResponse::InvalidPosition => None,
26706                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
26707                        // Fallback on using TreeSitter info to determine identifier range
26708                        buffer.read_with(cx, |buffer, _| {
26709                            let snapshot = buffer.snapshot();
26710                            let (range, kind) = snapshot.surrounding_word(position, None);
26711                            if kind != Some(CharKind::Word) {
26712                                return None;
26713                            }
26714                            Some(
26715                                snapshot.anchor_before(range.start)
26716                                    ..snapshot.anchor_after(range.end),
26717                            )
26718                        })
26719                    }
26720                })
26721            })
26722        }))
26723    }
26724
26725    fn perform_rename(
26726        &self,
26727        buffer: &Entity<Buffer>,
26728        position: text::Anchor,
26729        new_name: String,
26730        cx: &mut App,
26731    ) -> Option<Task<Result<ProjectTransaction>>> {
26732        Some(self.update(cx, |project, cx| {
26733            project.perform_rename(buffer.clone(), position, new_name, cx)
26734        }))
26735    }
26736}
26737
26738fn consume_contiguous_rows(
26739    contiguous_row_selections: &mut Vec<Selection<Point>>,
26740    selection: &Selection<Point>,
26741    display_map: &DisplaySnapshot,
26742    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
26743) -> (MultiBufferRow, MultiBufferRow) {
26744    contiguous_row_selections.push(selection.clone());
26745    let start_row = starting_row(selection, display_map);
26746    let mut end_row = ending_row(selection, display_map);
26747
26748    while let Some(next_selection) = selections.peek() {
26749        if next_selection.start.row <= end_row.0 {
26750            end_row = ending_row(next_selection, display_map);
26751            contiguous_row_selections.push(selections.next().unwrap().clone());
26752        } else {
26753            break;
26754        }
26755    }
26756    (start_row, end_row)
26757}
26758
26759fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
26760    if selection.start.column > 0 {
26761        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
26762    } else {
26763        MultiBufferRow(selection.start.row)
26764    }
26765}
26766
26767fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
26768    if next_selection.end.column > 0 || next_selection.is_empty() {
26769        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
26770    } else {
26771        MultiBufferRow(next_selection.end.row)
26772    }
26773}
26774
26775impl EditorSnapshot {
26776    pub fn remote_selections_in_range<'a>(
26777        &'a self,
26778        range: &'a Range<Anchor>,
26779        collaboration_hub: &dyn CollaborationHub,
26780        cx: &'a App,
26781    ) -> impl 'a + Iterator<Item = RemoteSelection> {
26782        let participant_names = collaboration_hub.user_names(cx);
26783        let participant_indices = collaboration_hub.user_participant_indices(cx);
26784        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
26785        let collaborators_by_replica_id = collaborators_by_peer_id
26786            .values()
26787            .map(|collaborator| (collaborator.replica_id, collaborator))
26788            .collect::<HashMap<_, _>>();
26789        self.buffer_snapshot()
26790            .selections_in_range(range, false)
26791            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
26792                if replica_id == ReplicaId::AGENT {
26793                    Some(RemoteSelection {
26794                        replica_id,
26795                        selection,
26796                        cursor_shape,
26797                        line_mode,
26798                        collaborator_id: CollaboratorId::Agent,
26799                        user_name: Some("Agent".into()),
26800                        color: cx.theme().players().agent(),
26801                    })
26802                } else {
26803                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
26804                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
26805                    let user_name = participant_names.get(&collaborator.user_id).cloned();
26806                    Some(RemoteSelection {
26807                        replica_id,
26808                        selection,
26809                        cursor_shape,
26810                        line_mode,
26811                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
26812                        user_name,
26813                        color: if let Some(index) = participant_index {
26814                            cx.theme().players().color_for_participant(index.0)
26815                        } else {
26816                            cx.theme().players().absent()
26817                        },
26818                    })
26819                }
26820            })
26821    }
26822
26823    pub fn hunks_for_ranges(
26824        &self,
26825        ranges: impl IntoIterator<Item = Range<Point>>,
26826    ) -> Vec<MultiBufferDiffHunk> {
26827        let mut hunks = Vec::new();
26828        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
26829            HashMap::default();
26830        for query_range in ranges {
26831            let query_rows =
26832                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
26833            for hunk in self.buffer_snapshot().diff_hunks_in_range(
26834                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
26835            ) {
26836                // Include deleted hunks that are adjacent to the query range, because
26837                // otherwise they would be missed.
26838                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
26839                if hunk.status().is_deleted() {
26840                    intersects_range |= hunk.row_range.start == query_rows.end;
26841                    intersects_range |= hunk.row_range.end == query_rows.start;
26842                }
26843                if intersects_range {
26844                    if !processed_buffer_rows
26845                        .entry(hunk.buffer_id)
26846                        .or_default()
26847                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
26848                    {
26849                        continue;
26850                    }
26851                    hunks.push(hunk);
26852                }
26853            }
26854        }
26855
26856        hunks
26857    }
26858
26859    fn display_diff_hunks_for_rows<'a>(
26860        &'a self,
26861        display_rows: Range<DisplayRow>,
26862        folded_buffers: &'a HashSet<BufferId>,
26863    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
26864        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
26865        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
26866
26867        self.buffer_snapshot()
26868            .diff_hunks_in_range(buffer_start..buffer_end)
26869            .filter_map(|hunk| {
26870                if folded_buffers.contains(&hunk.buffer_id) {
26871                    return None;
26872                }
26873
26874                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
26875                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
26876
26877                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
26878                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
26879
26880                let display_hunk = if hunk_display_start.column() != 0 {
26881                    DisplayDiffHunk::Folded {
26882                        display_row: hunk_display_start.row(),
26883                    }
26884                } else {
26885                    let mut end_row = hunk_display_end.row();
26886                    if hunk_display_end.column() > 0 {
26887                        end_row.0 += 1;
26888                    }
26889                    let is_created_file = hunk.is_created_file();
26890
26891                    DisplayDiffHunk::Unfolded {
26892                        status: hunk.status(),
26893                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
26894                            ..hunk.diff_base_byte_range.end.0,
26895                        word_diffs: hunk.word_diffs,
26896                        display_row_range: hunk_display_start.row()..end_row,
26897                        multi_buffer_range: Anchor::range_in_buffer(
26898                            hunk.excerpt_id,
26899                            hunk.buffer_range,
26900                        ),
26901                        is_created_file,
26902                    }
26903                };
26904
26905                Some(display_hunk)
26906            })
26907    }
26908
26909    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
26910        self.display_snapshot
26911            .buffer_snapshot()
26912            .language_at(position)
26913    }
26914
26915    pub fn is_focused(&self) -> bool {
26916        self.is_focused
26917    }
26918
26919    pub fn placeholder_text(&self) -> Option<String> {
26920        self.placeholder_display_snapshot
26921            .as_ref()
26922            .map(|display_map| display_map.text())
26923    }
26924
26925    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
26926        self.scroll_anchor.scroll_position(&self.display_snapshot)
26927    }
26928
26929    pub fn gutter_dimensions(
26930        &self,
26931        font_id: FontId,
26932        font_size: Pixels,
26933        style: &EditorStyle,
26934        window: &mut Window,
26935        cx: &App,
26936    ) -> GutterDimensions {
26937        if self.show_gutter
26938            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
26939            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
26940        {
26941            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
26942                matches!(
26943                    ProjectSettings::get_global(cx).git.git_gutter,
26944                    GitGutterSetting::TrackedFiles
26945                )
26946            });
26947            let gutter_settings = EditorSettings::get_global(cx).gutter;
26948            let show_line_numbers = self
26949                .show_line_numbers
26950                .unwrap_or(gutter_settings.line_numbers);
26951            let line_gutter_width = if show_line_numbers {
26952                // Avoid flicker-like gutter resizes when the line number gains another digit by
26953                // only resizing the gutter on files with > 10**min_line_number_digits lines.
26954                let min_width_for_number_on_gutter =
26955                    ch_advance * gutter_settings.min_line_number_digits as f32;
26956                self.max_line_number_width(style, window)
26957                    .max(min_width_for_number_on_gutter)
26958            } else {
26959                0.0.into()
26960            };
26961
26962            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
26963            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
26964
26965            let git_blame_entries_width =
26966                self.git_blame_gutter_max_author_length
26967                    .map(|max_author_length| {
26968                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
26969                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
26970
26971                        /// The number of characters to dedicate to gaps and margins.
26972                        const SPACING_WIDTH: usize = 4;
26973
26974                        let max_char_count = max_author_length.min(renderer.max_author_length())
26975                            + ::git::SHORT_SHA_LENGTH
26976                            + MAX_RELATIVE_TIMESTAMP.len()
26977                            + SPACING_WIDTH;
26978
26979                        ch_advance * max_char_count
26980                    });
26981
26982            let is_singleton = self.buffer_snapshot().is_singleton();
26983
26984            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
26985            left_padding += if !is_singleton {
26986                ch_width * 4.0
26987            } else if show_runnables || show_breakpoints {
26988                ch_width * 3.0
26989            } else if show_git_gutter && show_line_numbers {
26990                ch_width * 2.0
26991            } else if show_git_gutter || show_line_numbers {
26992                ch_width
26993            } else {
26994                px(0.)
26995            };
26996
26997            let shows_folds = is_singleton && gutter_settings.folds;
26998
26999            let right_padding = if shows_folds && show_line_numbers {
27000                ch_width * 4.0
27001            } else if shows_folds || (!is_singleton && show_line_numbers) {
27002                ch_width * 3.0
27003            } else if show_line_numbers {
27004                ch_width
27005            } else {
27006                px(0.)
27007            };
27008
27009            GutterDimensions {
27010                left_padding,
27011                right_padding,
27012                width: line_gutter_width + left_padding + right_padding,
27013                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
27014                git_blame_entries_width,
27015            }
27016        } else if self.offset_content {
27017            GutterDimensions::default_with_margin(font_id, font_size, cx)
27018        } else {
27019            GutterDimensions::default()
27020        }
27021    }
27022
27023    pub fn render_crease_toggle(
27024        &self,
27025        buffer_row: MultiBufferRow,
27026        row_contains_cursor: bool,
27027        editor: Entity<Editor>,
27028        window: &mut Window,
27029        cx: &mut App,
27030    ) -> Option<AnyElement> {
27031        let folded = self.is_line_folded(buffer_row);
27032        let mut is_foldable = false;
27033
27034        if let Some(crease) = self
27035            .crease_snapshot
27036            .query_row(buffer_row, self.buffer_snapshot())
27037        {
27038            is_foldable = true;
27039            match crease {
27040                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
27041                    if let Some(render_toggle) = render_toggle {
27042                        let toggle_callback =
27043                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
27044                                if folded {
27045                                    editor.update(cx, |editor, cx| {
27046                                        editor.fold_at(buffer_row, window, cx)
27047                                    });
27048                                } else {
27049                                    editor.update(cx, |editor, cx| {
27050                                        editor.unfold_at(buffer_row, window, cx)
27051                                    });
27052                                }
27053                            });
27054                        return Some((render_toggle)(
27055                            buffer_row,
27056                            folded,
27057                            toggle_callback,
27058                            window,
27059                            cx,
27060                        ));
27061                    }
27062                }
27063            }
27064        }
27065
27066        is_foldable |= self.starts_indent(buffer_row);
27067
27068        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
27069            Some(
27070                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
27071                    .toggle_state(folded)
27072                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
27073                        if folded {
27074                            this.unfold_at(buffer_row, window, cx);
27075                        } else {
27076                            this.fold_at(buffer_row, window, cx);
27077                        }
27078                    }))
27079                    .into_any_element(),
27080            )
27081        } else {
27082            None
27083        }
27084    }
27085
27086    pub fn render_crease_trailer(
27087        &self,
27088        buffer_row: MultiBufferRow,
27089        window: &mut Window,
27090        cx: &mut App,
27091    ) -> Option<AnyElement> {
27092        let folded = self.is_line_folded(buffer_row);
27093        if let Crease::Inline { render_trailer, .. } = self
27094            .crease_snapshot
27095            .query_row(buffer_row, self.buffer_snapshot())?
27096        {
27097            let render_trailer = render_trailer.as_ref()?;
27098            Some(render_trailer(buffer_row, folded, window, cx))
27099        } else {
27100            None
27101        }
27102    }
27103
27104    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
27105        let digit_count = self.widest_line_number().ilog10() + 1;
27106        column_pixels(style, digit_count as usize, window)
27107    }
27108
27109    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
27110    ///
27111    /// This is positive if `base` is before `line`.
27112    fn relative_line_delta(
27113        &self,
27114        current_selection_head: DisplayRow,
27115        first_visible_row: DisplayRow,
27116        consider_wrapped_lines: bool,
27117    ) -> i64 {
27118        let current_selection_head = current_selection_head.as_display_point().to_point(self);
27119        let first_visible_row = first_visible_row.as_display_point().to_point(self);
27120
27121        if consider_wrapped_lines {
27122            let wrap_snapshot = self.wrap_snapshot();
27123            let base_wrap_row = wrap_snapshot
27124                .make_wrap_point(current_selection_head, Bias::Left)
27125                .row();
27126            let wrap_row = wrap_snapshot
27127                .make_wrap_point(first_visible_row, Bias::Left)
27128                .row();
27129
27130            wrap_row.0 as i64 - base_wrap_row.0 as i64
27131        } else {
27132            let fold_snapshot = self.fold_snapshot();
27133            let base_fold_row = fold_snapshot
27134                .to_fold_point(self.to_inlay_point(current_selection_head), Bias::Left)
27135                .row();
27136            let fold_row = fold_snapshot
27137                .to_fold_point(self.to_inlay_point(first_visible_row), Bias::Left)
27138                .row();
27139
27140            fold_row as i64 - base_fold_row as i64
27141        }
27142    }
27143
27144    /// Returns the unsigned relative line number to display for each row in `rows`.
27145    ///
27146    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
27147    pub fn calculate_relative_line_numbers(
27148        &self,
27149        rows: &Range<DisplayRow>,
27150        current_selection_head: DisplayRow,
27151        count_wrapped_lines: bool,
27152    ) -> HashMap<DisplayRow, u32> {
27153        let initial_offset =
27154            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
27155        let current_selection_point = current_selection_head.as_display_point().to_point(self);
27156
27157        self.row_infos(rows.start)
27158            .take(rows.len())
27159            .enumerate()
27160            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
27161            .filter(|(_row, row_info)| {
27162                row_info.buffer_row.is_some()
27163                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
27164            })
27165            .enumerate()
27166            .filter(|(_, (row, row_info))| {
27167                // We want to check here that
27168                // - the row is not the current selection head to ensure the current
27169                // line has absolute numbering
27170                // - similarly, should the selection head live in a soft-wrapped line
27171                // and we are not counting those, that the parent line keeps its
27172                // absolute number
27173                // - lastly, if we are in a deleted line, it is fine to number this
27174                // relative with 0, as otherwise it would have no line number at all
27175                (*row != current_selection_head
27176                    && (count_wrapped_lines
27177                        || row_info.buffer_row != Some(current_selection_point.row)))
27178                    || row_info
27179                        .diff_status
27180                        .is_some_and(|status| status.is_deleted())
27181            })
27182            .map(|(i, (row, _))| (row, (initial_offset + i as i64).unsigned_abs() as u32))
27183            .collect()
27184    }
27185}
27186
27187pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
27188    let font_size = style.text.font_size.to_pixels(window.rem_size());
27189    let layout = window.text_system().shape_line(
27190        SharedString::from(" ".repeat(column)),
27191        font_size,
27192        &[TextRun {
27193            len: column,
27194            font: style.text.font(),
27195            color: Hsla::default(),
27196            ..Default::default()
27197        }],
27198        None,
27199    );
27200
27201    layout.width
27202}
27203
27204impl Deref for EditorSnapshot {
27205    type Target = DisplaySnapshot;
27206
27207    fn deref(&self) -> &Self::Target {
27208        &self.display_snapshot
27209    }
27210}
27211
27212#[derive(Clone, Debug, PartialEq, Eq)]
27213pub enum EditorEvent {
27214    /// Emitted when the stored review comments change (added, removed, or updated).
27215    ReviewCommentsChanged {
27216        /// The new total count of review comments.
27217        total_count: usize,
27218    },
27219    InputIgnored {
27220        text: Arc<str>,
27221    },
27222    InputHandled {
27223        utf16_range_to_replace: Option<Range<isize>>,
27224        text: Arc<str>,
27225    },
27226    ExcerptsAdded {
27227        buffer: Entity<Buffer>,
27228        predecessor: ExcerptId,
27229        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
27230    },
27231    ExcerptsRemoved {
27232        ids: Vec<ExcerptId>,
27233        removed_buffer_ids: Vec<BufferId>,
27234    },
27235    BufferFoldToggled {
27236        ids: Vec<ExcerptId>,
27237        folded: bool,
27238    },
27239    ExcerptsEdited {
27240        ids: Vec<ExcerptId>,
27241    },
27242    ExcerptsExpanded {
27243        ids: Vec<ExcerptId>,
27244    },
27245    ExpandExcerptsRequested {
27246        excerpt_ids: Vec<ExcerptId>,
27247        lines: u32,
27248        direction: ExpandExcerptDirection,
27249    },
27250    BufferEdited,
27251    Edited {
27252        transaction_id: clock::Lamport,
27253    },
27254    Reparsed(BufferId),
27255    Focused,
27256    FocusedIn,
27257    Blurred,
27258    DirtyChanged,
27259    Saved,
27260    TitleChanged,
27261    SelectionsChanged {
27262        local: bool,
27263    },
27264    ScrollPositionChanged {
27265        local: bool,
27266        autoscroll: bool,
27267    },
27268    TransactionUndone {
27269        transaction_id: clock::Lamport,
27270    },
27271    TransactionBegun {
27272        transaction_id: clock::Lamport,
27273    },
27274    CursorShapeChanged,
27275    BreadcrumbsChanged,
27276    PushedToNavHistory {
27277        anchor: Anchor,
27278        is_deactivate: bool,
27279    },
27280}
27281
27282impl EventEmitter<EditorEvent> for Editor {}
27283
27284impl Focusable for Editor {
27285    fn focus_handle(&self, _cx: &App) -> FocusHandle {
27286        self.focus_handle.clone()
27287    }
27288}
27289
27290impl Render for Editor {
27291    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
27292        EditorElement::new(&cx.entity(), self.create_style(cx))
27293    }
27294}
27295
27296impl EntityInputHandler for Editor {
27297    fn text_for_range(
27298        &mut self,
27299        range_utf16: Range<usize>,
27300        adjusted_range: &mut Option<Range<usize>>,
27301        _: &mut Window,
27302        cx: &mut Context<Self>,
27303    ) -> Option<String> {
27304        let snapshot = self.buffer.read(cx).read(cx);
27305        let start = snapshot.clip_offset_utf16(
27306            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
27307            Bias::Left,
27308        );
27309        let end = snapshot.clip_offset_utf16(
27310            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
27311            Bias::Right,
27312        );
27313        if (start.0.0..end.0.0) != range_utf16 {
27314            adjusted_range.replace(start.0.0..end.0.0);
27315        }
27316        Some(snapshot.text_for_range(start..end).collect())
27317    }
27318
27319    fn selected_text_range(
27320        &mut self,
27321        ignore_disabled_input: bool,
27322        _: &mut Window,
27323        cx: &mut Context<Self>,
27324    ) -> Option<UTF16Selection> {
27325        // Prevent the IME menu from appearing when holding down an alphabetic key
27326        // while input is disabled.
27327        if !ignore_disabled_input && !self.input_enabled {
27328            return None;
27329        }
27330
27331        let selection = self
27332            .selections
27333            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
27334        let range = selection.range();
27335
27336        Some(UTF16Selection {
27337            range: range.start.0.0..range.end.0.0,
27338            reversed: selection.reversed,
27339        })
27340    }
27341
27342    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
27343        let snapshot = self.buffer.read(cx).read(cx);
27344        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
27345        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
27346    }
27347
27348    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
27349        self.clear_highlights::<InputComposition>(cx);
27350        self.ime_transaction.take();
27351    }
27352
27353    fn replace_text_in_range(
27354        &mut self,
27355        range_utf16: Option<Range<usize>>,
27356        text: &str,
27357        window: &mut Window,
27358        cx: &mut Context<Self>,
27359    ) {
27360        if !self.input_enabled {
27361            cx.emit(EditorEvent::InputIgnored { text: text.into() });
27362            return;
27363        }
27364
27365        self.transact(window, cx, |this, window, cx| {
27366            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
27367                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
27368                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
27369                Some(this.selection_replacement_ranges(range_utf16, cx))
27370            } else {
27371                this.marked_text_ranges(cx)
27372            };
27373
27374            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
27375                let newest_selection_id = this.selections.newest_anchor().id;
27376                this.selections
27377                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
27378                    .iter()
27379                    .zip(ranges_to_replace.iter())
27380                    .find_map(|(selection, range)| {
27381                        if selection.id == newest_selection_id {
27382                            Some(
27383                                (range.start.0.0 as isize - selection.head().0.0 as isize)
27384                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
27385                            )
27386                        } else {
27387                            None
27388                        }
27389                    })
27390            });
27391
27392            cx.emit(EditorEvent::InputHandled {
27393                utf16_range_to_replace: range_to_replace,
27394                text: text.into(),
27395            });
27396
27397            if let Some(new_selected_ranges) = new_selected_ranges {
27398                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
27399                    selections.select_ranges(new_selected_ranges)
27400                });
27401                this.backspace(&Default::default(), window, cx);
27402            }
27403
27404            this.handle_input(text, window, cx);
27405        });
27406
27407        if let Some(transaction) = self.ime_transaction {
27408            self.buffer.update(cx, |buffer, cx| {
27409                buffer.group_until_transaction(transaction, cx);
27410            });
27411        }
27412
27413        self.unmark_text(window, cx);
27414    }
27415
27416    fn replace_and_mark_text_in_range(
27417        &mut self,
27418        range_utf16: Option<Range<usize>>,
27419        text: &str,
27420        new_selected_range_utf16: Option<Range<usize>>,
27421        window: &mut Window,
27422        cx: &mut Context<Self>,
27423    ) {
27424        if !self.input_enabled {
27425            return;
27426        }
27427
27428        let transaction = self.transact(window, cx, |this, window, cx| {
27429            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
27430                let snapshot = this.buffer.read(cx).read(cx);
27431                if let Some(relative_range_utf16) = range_utf16.as_ref() {
27432                    for marked_range in &mut marked_ranges {
27433                        marked_range.end = marked_range.start + relative_range_utf16.end;
27434                        marked_range.start += relative_range_utf16.start;
27435                        marked_range.start =
27436                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
27437                        marked_range.end =
27438                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
27439                    }
27440                }
27441                Some(marked_ranges)
27442            } else if let Some(range_utf16) = range_utf16 {
27443                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
27444                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
27445                Some(this.selection_replacement_ranges(range_utf16, cx))
27446            } else {
27447                None
27448            };
27449
27450            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
27451                let newest_selection_id = this.selections.newest_anchor().id;
27452                this.selections
27453                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
27454                    .iter()
27455                    .zip(ranges_to_replace.iter())
27456                    .find_map(|(selection, range)| {
27457                        if selection.id == newest_selection_id {
27458                            Some(
27459                                (range.start.0.0 as isize - selection.head().0.0 as isize)
27460                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
27461                            )
27462                        } else {
27463                            None
27464                        }
27465                    })
27466            });
27467
27468            cx.emit(EditorEvent::InputHandled {
27469                utf16_range_to_replace: range_to_replace,
27470                text: text.into(),
27471            });
27472
27473            if let Some(ranges) = ranges_to_replace {
27474                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
27475                    s.select_ranges(ranges)
27476                });
27477            }
27478
27479            let marked_ranges = {
27480                let snapshot = this.buffer.read(cx).read(cx);
27481                this.selections
27482                    .disjoint_anchors_arc()
27483                    .iter()
27484                    .map(|selection| {
27485                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
27486                    })
27487                    .collect::<Vec<_>>()
27488            };
27489
27490            if text.is_empty() {
27491                this.unmark_text(window, cx);
27492            } else {
27493                this.highlight_text::<InputComposition>(
27494                    marked_ranges.clone(),
27495                    HighlightStyle {
27496                        underline: Some(UnderlineStyle {
27497                            thickness: px(1.),
27498                            color: None,
27499                            wavy: false,
27500                        }),
27501                        ..Default::default()
27502                    },
27503                    cx,
27504                );
27505            }
27506
27507            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
27508            let use_autoclose = this.use_autoclose;
27509            let use_auto_surround = this.use_auto_surround;
27510            this.set_use_autoclose(false);
27511            this.set_use_auto_surround(false);
27512            this.handle_input(text, window, cx);
27513            this.set_use_autoclose(use_autoclose);
27514            this.set_use_auto_surround(use_auto_surround);
27515
27516            if let Some(new_selected_range) = new_selected_range_utf16 {
27517                let snapshot = this.buffer.read(cx).read(cx);
27518                let new_selected_ranges = marked_ranges
27519                    .into_iter()
27520                    .map(|marked_range| {
27521                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
27522                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
27523                            insertion_start.0 + new_selected_range.start,
27524                        ));
27525                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
27526                            insertion_start.0 + new_selected_range.end,
27527                        ));
27528                        snapshot.clip_offset_utf16(new_start, Bias::Left)
27529                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
27530                    })
27531                    .collect::<Vec<_>>();
27532
27533                drop(snapshot);
27534                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
27535                    selections.select_ranges(new_selected_ranges)
27536                });
27537            }
27538        });
27539
27540        self.ime_transaction = self.ime_transaction.or(transaction);
27541        if let Some(transaction) = self.ime_transaction {
27542            self.buffer.update(cx, |buffer, cx| {
27543                buffer.group_until_transaction(transaction, cx);
27544            });
27545        }
27546
27547        if self.text_highlights::<InputComposition>(cx).is_none() {
27548            self.ime_transaction.take();
27549        }
27550    }
27551
27552    fn bounds_for_range(
27553        &mut self,
27554        range_utf16: Range<usize>,
27555        element_bounds: gpui::Bounds<Pixels>,
27556        window: &mut Window,
27557        cx: &mut Context<Self>,
27558    ) -> Option<gpui::Bounds<Pixels>> {
27559        let text_layout_details = self.text_layout_details(window);
27560        let CharacterDimensions {
27561            em_width,
27562            em_advance,
27563            line_height,
27564        } = self.character_dimensions(window);
27565
27566        let snapshot = self.snapshot(window, cx);
27567        let scroll_position = snapshot.scroll_position();
27568        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
27569
27570        let start =
27571            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
27572        let x = Pixels::from(
27573            ScrollOffset::from(
27574                snapshot.x_for_display_point(start, &text_layout_details)
27575                    + self.gutter_dimensions.full_width(),
27576            ) - scroll_left,
27577        );
27578        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
27579
27580        Some(Bounds {
27581            origin: element_bounds.origin + point(x, y),
27582            size: size(em_width, line_height),
27583        })
27584    }
27585
27586    fn character_index_for_point(
27587        &mut self,
27588        point: gpui::Point<Pixels>,
27589        _window: &mut Window,
27590        _cx: &mut Context<Self>,
27591    ) -> Option<usize> {
27592        let position_map = self.last_position_map.as_ref()?;
27593        if !position_map.text_hitbox.contains(&point) {
27594            return None;
27595        }
27596        let display_point = position_map.point_for_position(point).previous_valid;
27597        let anchor = position_map
27598            .snapshot
27599            .display_point_to_anchor(display_point, Bias::Left);
27600        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
27601        Some(utf16_offset.0.0)
27602    }
27603
27604    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
27605        self.input_enabled
27606    }
27607}
27608
27609trait SelectionExt {
27610    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
27611    fn spanned_rows(
27612        &self,
27613        include_end_if_at_line_start: bool,
27614        map: &DisplaySnapshot,
27615    ) -> Range<MultiBufferRow>;
27616}
27617
27618impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
27619    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
27620        let start = self
27621            .start
27622            .to_point(map.buffer_snapshot())
27623            .to_display_point(map);
27624        let end = self
27625            .end
27626            .to_point(map.buffer_snapshot())
27627            .to_display_point(map);
27628        if self.reversed {
27629            end..start
27630        } else {
27631            start..end
27632        }
27633    }
27634
27635    fn spanned_rows(
27636        &self,
27637        include_end_if_at_line_start: bool,
27638        map: &DisplaySnapshot,
27639    ) -> Range<MultiBufferRow> {
27640        let start = self.start.to_point(map.buffer_snapshot());
27641        let mut end = self.end.to_point(map.buffer_snapshot());
27642        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
27643            end.row -= 1;
27644        }
27645
27646        let buffer_start = map.prev_line_boundary(start).0;
27647        let buffer_end = map.next_line_boundary(end).0;
27648        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
27649    }
27650}
27651
27652impl<T: InvalidationRegion> InvalidationStack<T> {
27653    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
27654    where
27655        S: Clone + ToOffset,
27656    {
27657        while let Some(region) = self.last() {
27658            let all_selections_inside_invalidation_ranges =
27659                if selections.len() == region.ranges().len() {
27660                    selections
27661                        .iter()
27662                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
27663                        .all(|(selection, invalidation_range)| {
27664                            let head = selection.head().to_offset(buffer);
27665                            invalidation_range.start <= head && invalidation_range.end >= head
27666                        })
27667                } else {
27668                    false
27669                };
27670
27671            if all_selections_inside_invalidation_ranges {
27672                break;
27673            } else {
27674                self.pop();
27675            }
27676        }
27677    }
27678}
27679
27680#[derive(Clone)]
27681struct ErasedEditorImpl(Entity<Editor>);
27682
27683impl ui_input::ErasedEditor for ErasedEditorImpl {
27684    fn text(&self, cx: &App) -> String {
27685        self.0.read(cx).text(cx)
27686    }
27687
27688    fn set_text(&self, text: &str, window: &mut Window, cx: &mut App) {
27689        self.0.update(cx, |this, cx| {
27690            this.set_text(text, window, cx);
27691        })
27692    }
27693
27694    fn clear(&self, window: &mut Window, cx: &mut App) {
27695        self.0.update(cx, |this, cx| this.clear(window, cx));
27696    }
27697
27698    fn set_placeholder_text(&self, text: &str, window: &mut Window, cx: &mut App) {
27699        self.0.update(cx, |this, cx| {
27700            this.set_placeholder_text(text, window, cx);
27701        });
27702    }
27703
27704    fn focus_handle(&self, cx: &App) -> FocusHandle {
27705        self.0.read(cx).focus_handle(cx)
27706    }
27707
27708    fn render(&self, _: &mut Window, cx: &App) -> AnyElement {
27709        let settings = ThemeSettings::get_global(cx);
27710        let theme_color = cx.theme().colors();
27711
27712        let text_style = TextStyle {
27713            font_family: settings.ui_font.family.clone(),
27714            font_features: settings.ui_font.features.clone(),
27715            font_size: rems(0.875).into(),
27716            font_weight: settings.buffer_font.weight,
27717            font_style: FontStyle::Normal,
27718            line_height: relative(1.2),
27719            color: theme_color.text,
27720            ..Default::default()
27721        };
27722        let editor_style = EditorStyle {
27723            background: theme_color.ghost_element_background,
27724            local_player: cx.theme().players().local(),
27725            syntax: cx.theme().syntax().clone(),
27726            text: text_style,
27727            ..Default::default()
27728        };
27729        EditorElement::new(&self.0, editor_style).into_any()
27730    }
27731
27732    fn as_any(&self) -> &dyn Any {
27733        &self.0
27734    }
27735
27736    fn move_selection_to_end(&self, window: &mut Window, cx: &mut App) {
27737        self.0.update(cx, |editor, cx| {
27738            let editor_offset = editor.buffer().read(cx).len(cx);
27739            editor.change_selections(
27740                SelectionEffects::scroll(Autoscroll::Next),
27741                window,
27742                cx,
27743                |s| s.select_ranges(Some(editor_offset..editor_offset)),
27744            );
27745        });
27746    }
27747
27748    fn subscribe(
27749        &self,
27750        mut callback: Box<dyn FnMut(ui_input::ErasedEditorEvent, &mut Window, &mut App) + 'static>,
27751        window: &mut Window,
27752        cx: &mut App,
27753    ) -> Subscription {
27754        window.subscribe(&self.0, cx, move |_, event: &EditorEvent, window, cx| {
27755            let event = match event {
27756                EditorEvent::BufferEdited => ui_input::ErasedEditorEvent::BufferEdited,
27757                EditorEvent::Blurred => ui_input::ErasedEditorEvent::Blurred,
27758                _ => return,
27759            };
27760            (callback)(event, window, cx);
27761        })
27762    }
27763}
27764impl<T> Default for InvalidationStack<T> {
27765    fn default() -> Self {
27766        Self(Default::default())
27767    }
27768}
27769
27770impl<T> Deref for InvalidationStack<T> {
27771    type Target = Vec<T>;
27772
27773    fn deref(&self) -> &Self::Target {
27774        &self.0
27775    }
27776}
27777
27778impl<T> DerefMut for InvalidationStack<T> {
27779    fn deref_mut(&mut self) -> &mut Self::Target {
27780        &mut self.0
27781    }
27782}
27783
27784impl InvalidationRegion for SnippetState {
27785    fn ranges(&self) -> &[Range<Anchor>] {
27786        &self.ranges[self.active_index]
27787    }
27788}
27789
27790fn edit_prediction_edit_text(
27791    current_snapshot: &BufferSnapshot,
27792    edits: &[(Range<Anchor>, impl AsRef<str>)],
27793    edit_preview: &EditPreview,
27794    include_deletions: bool,
27795    cx: &App,
27796) -> HighlightedText {
27797    let edits = edits
27798        .iter()
27799        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
27800        .collect::<Vec<_>>();
27801
27802    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
27803}
27804
27805fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
27806    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
27807    // Just show the raw edit text with basic styling
27808    let mut text = String::new();
27809    let mut highlights = Vec::new();
27810
27811    let insertion_highlight_style = HighlightStyle {
27812        color: Some(cx.theme().colors().text),
27813        ..Default::default()
27814    };
27815
27816    for (_, edit_text) in edits {
27817        let start_offset = text.len();
27818        text.push_str(edit_text);
27819        let end_offset = text.len();
27820
27821        if start_offset < end_offset {
27822            highlights.push((start_offset..end_offset, insertion_highlight_style));
27823        }
27824    }
27825
27826    HighlightedText {
27827        text: text.into(),
27828        highlights,
27829    }
27830}
27831
27832pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
27833    match severity {
27834        lsp::DiagnosticSeverity::ERROR => colors.error,
27835        lsp::DiagnosticSeverity::WARNING => colors.warning,
27836        lsp::DiagnosticSeverity::INFORMATION => colors.info,
27837        lsp::DiagnosticSeverity::HINT => colors.info,
27838        _ => colors.ignored,
27839    }
27840}
27841
27842pub fn styled_runs_for_code_label<'a>(
27843    label: &'a CodeLabel,
27844    syntax_theme: &'a theme::SyntaxTheme,
27845    local_player: &'a theme::PlayerColor,
27846) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
27847    let fade_out = HighlightStyle {
27848        fade_out: Some(0.35),
27849        ..Default::default()
27850    };
27851
27852    let mut prev_end = label.filter_range.end;
27853    label
27854        .runs
27855        .iter()
27856        .enumerate()
27857        .flat_map(move |(ix, (range, highlight_id))| {
27858            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
27859                HighlightStyle {
27860                    color: Some(local_player.cursor),
27861                    ..Default::default()
27862                }
27863            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
27864                HighlightStyle {
27865                    background_color: Some(local_player.selection),
27866                    ..Default::default()
27867                }
27868            } else if let Some(style) = highlight_id.style(syntax_theme) {
27869                style
27870            } else {
27871                return Default::default();
27872            };
27873            let muted_style = style.highlight(fade_out);
27874
27875            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
27876            if range.start >= label.filter_range.end {
27877                if range.start > prev_end {
27878                    runs.push((prev_end..range.start, fade_out));
27879                }
27880                runs.push((range.clone(), muted_style));
27881            } else if range.end <= label.filter_range.end {
27882                runs.push((range.clone(), style));
27883            } else {
27884                runs.push((range.start..label.filter_range.end, style));
27885                runs.push((label.filter_range.end..range.end, muted_style));
27886            }
27887            prev_end = cmp::max(prev_end, range.end);
27888
27889            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
27890                runs.push((prev_end..label.text.len(), fade_out));
27891            }
27892
27893            runs
27894        })
27895}
27896
27897pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
27898    let mut prev_index = 0;
27899    let mut prev_codepoint: Option<char> = None;
27900    text.char_indices()
27901        .chain([(text.len(), '\0')])
27902        .filter_map(move |(index, codepoint)| {
27903            let prev_codepoint = prev_codepoint.replace(codepoint)?;
27904            let is_boundary = index == text.len()
27905                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
27906                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
27907            if is_boundary {
27908                let chunk = &text[prev_index..index];
27909                prev_index = index;
27910                Some(chunk)
27911            } else {
27912                None
27913            }
27914        })
27915}
27916
27917/// Given a string of text immediately before the cursor, iterates over possible
27918/// strings a snippet could match to. More precisely: returns an iterator over
27919/// suffixes of `text` created by splitting at word boundaries (before & after
27920/// every non-word character).
27921///
27922/// Shorter suffixes are returned first.
27923pub(crate) fn snippet_candidate_suffixes(
27924    text: &str,
27925    is_word_char: impl Fn(char) -> bool,
27926) -> impl std::iter::Iterator<Item = &str> {
27927    let mut prev_index = text.len();
27928    let mut prev_codepoint = None;
27929    text.char_indices()
27930        .rev()
27931        .chain([(0, '\0')])
27932        .filter_map(move |(index, codepoint)| {
27933            let prev_index = std::mem::replace(&mut prev_index, index);
27934            let prev_codepoint = prev_codepoint.replace(codepoint)?;
27935            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
27936                None
27937            } else {
27938                let chunk = &text[prev_index..]; // go to end of string
27939                Some(chunk)
27940            }
27941        })
27942}
27943
27944pub trait RangeToAnchorExt: Sized {
27945    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
27946
27947    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
27948        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
27949        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
27950    }
27951}
27952
27953impl<T: ToOffset> RangeToAnchorExt for Range<T> {
27954    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
27955        let start_offset = self.start.to_offset(snapshot);
27956        let end_offset = self.end.to_offset(snapshot);
27957        if start_offset == end_offset {
27958            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
27959        } else {
27960            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
27961        }
27962    }
27963}
27964
27965pub trait RowExt {
27966    fn as_f64(&self) -> f64;
27967
27968    fn next_row(&self) -> Self;
27969
27970    fn previous_row(&self) -> Self;
27971
27972    fn minus(&self, other: Self) -> u32;
27973}
27974
27975impl RowExt for DisplayRow {
27976    fn as_f64(&self) -> f64 {
27977        self.0 as _
27978    }
27979
27980    fn next_row(&self) -> Self {
27981        Self(self.0 + 1)
27982    }
27983
27984    fn previous_row(&self) -> Self {
27985        Self(self.0.saturating_sub(1))
27986    }
27987
27988    fn minus(&self, other: Self) -> u32 {
27989        self.0 - other.0
27990    }
27991}
27992
27993impl RowExt for MultiBufferRow {
27994    fn as_f64(&self) -> f64 {
27995        self.0 as _
27996    }
27997
27998    fn next_row(&self) -> Self {
27999        Self(self.0 + 1)
28000    }
28001
28002    fn previous_row(&self) -> Self {
28003        Self(self.0.saturating_sub(1))
28004    }
28005
28006    fn minus(&self, other: Self) -> u32 {
28007        self.0 - other.0
28008    }
28009}
28010
28011trait RowRangeExt {
28012    type Row;
28013
28014    fn len(&self) -> usize;
28015
28016    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
28017}
28018
28019impl RowRangeExt for Range<MultiBufferRow> {
28020    type Row = MultiBufferRow;
28021
28022    fn len(&self) -> usize {
28023        (self.end.0 - self.start.0) as usize
28024    }
28025
28026    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
28027        (self.start.0..self.end.0).map(MultiBufferRow)
28028    }
28029}
28030
28031impl RowRangeExt for Range<DisplayRow> {
28032    type Row = DisplayRow;
28033
28034    fn len(&self) -> usize {
28035        (self.end.0 - self.start.0) as usize
28036    }
28037
28038    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
28039        (self.start.0..self.end.0).map(DisplayRow)
28040    }
28041}
28042
28043/// If select range has more than one line, we
28044/// just point the cursor to range.start.
28045fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
28046    if range.start.row == range.end.row {
28047        range
28048    } else {
28049        range.start..range.start
28050    }
28051}
28052pub struct KillRing(ClipboardItem);
28053impl Global for KillRing {}
28054
28055const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
28056
28057enum BreakpointPromptEditAction {
28058    Log,
28059    Condition,
28060    HitCondition,
28061}
28062
28063struct BreakpointPromptEditor {
28064    pub(crate) prompt: Entity<Editor>,
28065    editor: WeakEntity<Editor>,
28066    breakpoint_anchor: Anchor,
28067    breakpoint: Breakpoint,
28068    edit_action: BreakpointPromptEditAction,
28069    block_ids: HashSet<CustomBlockId>,
28070    editor_margins: Arc<Mutex<EditorMargins>>,
28071    _subscriptions: Vec<Subscription>,
28072}
28073
28074impl BreakpointPromptEditor {
28075    const MAX_LINES: u8 = 4;
28076
28077    fn new(
28078        editor: WeakEntity<Editor>,
28079        breakpoint_anchor: Anchor,
28080        breakpoint: Breakpoint,
28081        edit_action: BreakpointPromptEditAction,
28082        window: &mut Window,
28083        cx: &mut Context<Self>,
28084    ) -> Self {
28085        let base_text = match edit_action {
28086            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
28087            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
28088            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
28089        }
28090        .map(|msg| msg.to_string())
28091        .unwrap_or_default();
28092
28093        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
28094        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
28095
28096        let prompt = cx.new(|cx| {
28097            let mut prompt = Editor::new(
28098                EditorMode::AutoHeight {
28099                    min_lines: 1,
28100                    max_lines: Some(Self::MAX_LINES as usize),
28101                },
28102                buffer,
28103                None,
28104                window,
28105                cx,
28106            );
28107            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
28108            prompt.set_show_cursor_when_unfocused(false, cx);
28109            prompt.set_placeholder_text(
28110                match edit_action {
28111                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
28112                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
28113                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
28114                },
28115                window,
28116                cx,
28117            );
28118
28119            prompt
28120        });
28121
28122        Self {
28123            prompt,
28124            editor,
28125            breakpoint_anchor,
28126            breakpoint,
28127            edit_action,
28128            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
28129            block_ids: Default::default(),
28130            _subscriptions: vec![],
28131        }
28132    }
28133
28134    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
28135        self.block_ids.extend(block_ids)
28136    }
28137
28138    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
28139        if let Some(editor) = self.editor.upgrade() {
28140            let message = self
28141                .prompt
28142                .read(cx)
28143                .buffer
28144                .read(cx)
28145                .as_singleton()
28146                .expect("A multi buffer in breakpoint prompt isn't possible")
28147                .read(cx)
28148                .as_rope()
28149                .to_string();
28150
28151            editor.update(cx, |editor, cx| {
28152                editor.edit_breakpoint_at_anchor(
28153                    self.breakpoint_anchor,
28154                    self.breakpoint.clone(),
28155                    match self.edit_action {
28156                        BreakpointPromptEditAction::Log => {
28157                            BreakpointEditAction::EditLogMessage(message.into())
28158                        }
28159                        BreakpointPromptEditAction::Condition => {
28160                            BreakpointEditAction::EditCondition(message.into())
28161                        }
28162                        BreakpointPromptEditAction::HitCondition => {
28163                            BreakpointEditAction::EditHitCondition(message.into())
28164                        }
28165                    },
28166                    cx,
28167                );
28168
28169                editor.remove_blocks(self.block_ids.clone(), None, cx);
28170                cx.focus_self(window);
28171            });
28172        }
28173    }
28174
28175    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
28176        self.editor
28177            .update(cx, |editor, cx| {
28178                editor.remove_blocks(self.block_ids.clone(), None, cx);
28179                window.focus(&editor.focus_handle, cx);
28180            })
28181            .log_err();
28182    }
28183
28184    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
28185        let settings = ThemeSettings::get_global(cx);
28186        let text_style = TextStyle {
28187            color: if self.prompt.read(cx).read_only(cx) {
28188                cx.theme().colors().text_disabled
28189            } else {
28190                cx.theme().colors().text
28191            },
28192            font_family: settings.buffer_font.family.clone(),
28193            font_fallbacks: settings.buffer_font.fallbacks.clone(),
28194            font_size: settings.buffer_font_size(cx).into(),
28195            font_weight: settings.buffer_font.weight,
28196            line_height: relative(settings.buffer_line_height.value()),
28197            ..Default::default()
28198        };
28199        EditorElement::new(
28200            &self.prompt,
28201            EditorStyle {
28202                background: cx.theme().colors().editor_background,
28203                local_player: cx.theme().players().local(),
28204                text: text_style,
28205                ..Default::default()
28206            },
28207        )
28208    }
28209}
28210
28211impl Render for BreakpointPromptEditor {
28212    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28213        let editor_margins = *self.editor_margins.lock();
28214        let gutter_dimensions = editor_margins.gutter;
28215        h_flex()
28216            .key_context("Editor")
28217            .bg(cx.theme().colors().editor_background)
28218            .border_y_1()
28219            .border_color(cx.theme().status().info_border)
28220            .size_full()
28221            .py(window.line_height() / 2.5)
28222            .on_action(cx.listener(Self::confirm))
28223            .on_action(cx.listener(Self::cancel))
28224            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
28225            .child(div().flex_1().child(self.render_prompt_editor(cx)))
28226    }
28227}
28228
28229impl Focusable for BreakpointPromptEditor {
28230    fn focus_handle(&self, cx: &App) -> FocusHandle {
28231        self.prompt.focus_handle(cx)
28232    }
28233}
28234
28235fn all_edits_insertions_or_deletions(
28236    edits: &Vec<(Range<Anchor>, Arc<str>)>,
28237    snapshot: &MultiBufferSnapshot,
28238) -> bool {
28239    let mut all_insertions = true;
28240    let mut all_deletions = true;
28241
28242    for (range, new_text) in edits.iter() {
28243        let range_is_empty = range.to_offset(snapshot).is_empty();
28244        let text_is_empty = new_text.is_empty();
28245
28246        if range_is_empty != text_is_empty {
28247            if range_is_empty {
28248                all_deletions = false;
28249            } else {
28250                all_insertions = false;
28251            }
28252        } else {
28253            return false;
28254        }
28255
28256        if !all_insertions && !all_deletions {
28257            return false;
28258        }
28259    }
28260    all_insertions || all_deletions
28261}
28262
28263struct MissingEditPredictionKeybindingTooltip;
28264
28265impl Render for MissingEditPredictionKeybindingTooltip {
28266    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28267        ui::tooltip_container(cx, |container, cx| {
28268            container
28269                .flex_shrink_0()
28270                .max_w_80()
28271                .min_h(rems_from_px(124.))
28272                .justify_between()
28273                .child(
28274                    v_flex()
28275                        .flex_1()
28276                        .text_ui_sm(cx)
28277                        .child(Label::new("Conflict with Accept Keybinding"))
28278                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
28279                )
28280                .child(
28281                    h_flex()
28282                        .pb_1()
28283                        .gap_1()
28284                        .items_end()
28285                        .w_full()
28286                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
28287                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
28288                        }))
28289                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
28290                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
28291                        })),
28292                )
28293        })
28294    }
28295}
28296
28297#[derive(Debug, Clone, Copy, PartialEq)]
28298pub struct LineHighlight {
28299    pub background: Background,
28300    pub border: Option<gpui::Hsla>,
28301    pub include_gutter: bool,
28302    pub type_id: Option<TypeId>,
28303}
28304
28305struct LineManipulationResult {
28306    pub new_text: String,
28307    pub line_count_before: usize,
28308    pub line_count_after: usize,
28309}
28310
28311fn render_diff_hunk_controls(
28312    row: u32,
28313    status: &DiffHunkStatus,
28314    hunk_range: Range<Anchor>,
28315    is_created_file: bool,
28316    line_height: Pixels,
28317    editor: &Entity<Editor>,
28318    _window: &mut Window,
28319    cx: &mut App,
28320) -> AnyElement {
28321    h_flex()
28322        .h(line_height)
28323        .mr_1()
28324        .gap_1()
28325        .px_0p5()
28326        .pb_1()
28327        .border_x_1()
28328        .border_b_1()
28329        .border_color(cx.theme().colors().border_variant)
28330        .rounded_b_lg()
28331        .bg(cx.theme().colors().editor_background)
28332        .gap_1()
28333        .block_mouse_except_scroll()
28334        .shadow_md()
28335        .child(if status.has_secondary_hunk() {
28336            Button::new(("stage", row as u64), "Stage")
28337                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
28338                .tooltip({
28339                    let focus_handle = editor.focus_handle(cx);
28340                    move |_window, cx| {
28341                        Tooltip::for_action_in(
28342                            "Stage Hunk",
28343                            &::git::ToggleStaged,
28344                            &focus_handle,
28345                            cx,
28346                        )
28347                    }
28348                })
28349                .on_click({
28350                    let editor = editor.clone();
28351                    move |_event, _window, cx| {
28352                        editor.update(cx, |editor, cx| {
28353                            editor.stage_or_unstage_diff_hunks(
28354                                true,
28355                                vec![hunk_range.start..hunk_range.start],
28356                                cx,
28357                            );
28358                        });
28359                    }
28360                })
28361        } else {
28362            Button::new(("unstage", row as u64), "Unstage")
28363                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
28364                .tooltip({
28365                    let focus_handle = editor.focus_handle(cx);
28366                    move |_window, cx| {
28367                        Tooltip::for_action_in(
28368                            "Unstage Hunk",
28369                            &::git::ToggleStaged,
28370                            &focus_handle,
28371                            cx,
28372                        )
28373                    }
28374                })
28375                .on_click({
28376                    let editor = editor.clone();
28377                    move |_event, _window, cx| {
28378                        editor.update(cx, |editor, cx| {
28379                            editor.stage_or_unstage_diff_hunks(
28380                                false,
28381                                vec![hunk_range.start..hunk_range.start],
28382                                cx,
28383                            );
28384                        });
28385                    }
28386                })
28387        })
28388        .child(
28389            Button::new(("restore", row as u64), "Restore")
28390                .tooltip({
28391                    let focus_handle = editor.focus_handle(cx);
28392                    move |_window, cx| {
28393                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
28394                    }
28395                })
28396                .on_click({
28397                    let editor = editor.clone();
28398                    move |_event, window, cx| {
28399                        editor.update(cx, |editor, cx| {
28400                            let snapshot = editor.snapshot(window, cx);
28401                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
28402                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
28403                        });
28404                    }
28405                })
28406                .disabled(is_created_file),
28407        )
28408        .when(
28409            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
28410            |el| {
28411                el.child(
28412                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
28413                        .shape(IconButtonShape::Square)
28414                        .icon_size(IconSize::Small)
28415                        // .disabled(!has_multiple_hunks)
28416                        .tooltip({
28417                            let focus_handle = editor.focus_handle(cx);
28418                            move |_window, cx| {
28419                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
28420                            }
28421                        })
28422                        .on_click({
28423                            let editor = editor.clone();
28424                            move |_event, window, cx| {
28425                                editor.update(cx, |editor, cx| {
28426                                    let snapshot = editor.snapshot(window, cx);
28427                                    let position =
28428                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
28429                                    editor.go_to_hunk_before_or_after_position(
28430                                        &snapshot,
28431                                        position,
28432                                        Direction::Next,
28433                                        window,
28434                                        cx,
28435                                    );
28436                                    editor.expand_selected_diff_hunks(cx);
28437                                });
28438                            }
28439                        }),
28440                )
28441                .child(
28442                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
28443                        .shape(IconButtonShape::Square)
28444                        .icon_size(IconSize::Small)
28445                        // .disabled(!has_multiple_hunks)
28446                        .tooltip({
28447                            let focus_handle = editor.focus_handle(cx);
28448                            move |_window, cx| {
28449                                Tooltip::for_action_in(
28450                                    "Previous Hunk",
28451                                    &GoToPreviousHunk,
28452                                    &focus_handle,
28453                                    cx,
28454                                )
28455                            }
28456                        })
28457                        .on_click({
28458                            let editor = editor.clone();
28459                            move |_event, window, cx| {
28460                                editor.update(cx, |editor, cx| {
28461                                    let snapshot = editor.snapshot(window, cx);
28462                                    let point =
28463                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
28464                                    editor.go_to_hunk_before_or_after_position(
28465                                        &snapshot,
28466                                        point,
28467                                        Direction::Prev,
28468                                        window,
28469                                        cx,
28470                                    );
28471                                    editor.expand_selected_diff_hunks(cx);
28472                                });
28473                            }
28474                        }),
28475                )
28476            },
28477        )
28478        .into_any_element()
28479}
28480
28481pub fn multibuffer_context_lines(cx: &App) -> u32 {
28482    EditorSettings::try_get(cx)
28483        .map(|settings| settings.excerpt_context_lines)
28484        .unwrap_or(2)
28485        .min(32)
28486}