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;
   15mod blink_manager;
   16mod clangd_ext;
   17pub mod code_context_menus;
   18pub mod display_map;
   19mod editor_settings;
   20mod element;
   21mod git;
   22mod highlight_matching_bracket;
   23mod hover_links;
   24pub mod hover_popover;
   25mod indent_guides;
   26mod inlays;
   27pub mod items;
   28mod jsx_tag_auto_close;
   29mod linked_editing_ranges;
   30mod lsp_colors;
   31mod lsp_ext;
   32mod mouse_context_menu;
   33pub mod movement;
   34mod persistence;
   35mod rust_analyzer_ext;
   36pub mod scroll;
   37mod selections_collection;
   38pub mod tasks;
   39
   40#[cfg(test)]
   41mod code_completion_tests;
   42#[cfg(test)]
   43mod edit_prediction_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46mod signature_help;
   47#[cfg(any(test, feature = "test-support"))]
   48pub mod test;
   49
   50pub(crate) use actions::*;
   51pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   52pub use edit_prediction::Direction;
   53pub use editor_settings::{
   54    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   55    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   56};
   57pub use element::{
   58    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   59};
   60pub use git::blame::BlameRenderer;
   61pub use hover_popover::hover_markdown_style;
   62pub use inlays::Inlay;
   63pub use items::MAX_TAB_TITLE_LEN;
   64pub use lsp::CompletionContext;
   65pub use lsp_ext::lsp_tasks;
   66pub use multi_buffer::{
   67    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   68    RowInfo, ToOffset, ToPoint,
   69};
   70pub use text::Bias;
   71
   72use ::git::{
   73    Restore,
   74    blame::{BlameEntry, ParsedCommitMessage},
   75    status::FileStatus,
   76};
   77use aho_corasick::AhoCorasick;
   78use anyhow::{Context as _, Result, anyhow};
   79use blink_manager::BlinkManager;
   80use buffer_diff::DiffHunkStatus;
   81use client::{Collaborator, ParticipantIndex, parse_zed_link};
   82use clock::ReplicaId;
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   88use convert_case::{Case, Casing};
   89use dap::TelemetrySpawnLocation;
   90use display_map::*;
   91use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   92use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   93use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   94use futures::{
   95    FutureExt, StreamExt as _,
   96    future::{self, Shared, join},
   97    stream::FuturesUnordered,
   98};
   99use fuzzy::{StringMatch, StringMatchCandidate};
  100use git::blame::{GitBlame, GlobalBlameRenderer};
  101use gpui::{
  102    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  103    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  104    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  105    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  106    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  107    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  108    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  109    div, point, prelude::*, pulsating_between, px, relative, size,
  110};
  111use hover_links::{HoverLink, HoveredLinkState, find_file};
  112use hover_popover::{HoverState, hide_hover};
  113use indent_guides::ActiveIndentGuidesState;
  114use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  115use itertools::{Either, Itertools};
  116use language::{
  117    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  118    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  119    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  120    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  121    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  122    language_settings::{
  123        self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
  124        language_settings,
  125    },
  126    point_from_lsp, point_to_lsp, text_diff_with_options,
  127};
  128use linked_editing_ranges::refresh_linked_ranges;
  129use lsp::{
  130    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  131    LanguageServerId,
  132};
  133use lsp_colors::LspColorData;
  134use markdown::Markdown;
  135use mouse_context_menu::MouseContextMenu;
  136use movement::TextLayoutDetails;
  137use multi_buffer::{
  138    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  139};
  140use parking_lot::Mutex;
  141use persistence::DB;
  142use project::{
  143    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  144    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  145    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  146    ProjectPath, ProjectTransaction, TaskSourceKind,
  147    debugger::{
  148        breakpoint_store::{
  149            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  150            BreakpointStore, BreakpointStoreEvent,
  151        },
  152        session::{Session, SessionEvent},
  153    },
  154    git_store::GitStoreEvent,
  155    lsp_store::{
  156        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  157        OpenLspBufferHandle,
  158    },
  159    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  160};
  161use rand::seq::SliceRandom;
  162use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  163use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  164use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  165use serde::{Deserialize, Serialize};
  166use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  167use smallvec::{SmallVec, smallvec};
  168use snippet::Snippet;
  169use std::{
  170    any::{Any, TypeId},
  171    borrow::Cow,
  172    cell::{OnceCell, RefCell},
  173    cmp::{self, Ordering, Reverse},
  174    iter::{self, Peekable},
  175    mem,
  176    num::NonZeroU32,
  177    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  178    path::{Path, PathBuf},
  179    rc::Rc,
  180    sync::Arc,
  181    time::{Duration, Instant},
  182};
  183use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  184use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  185use theme::{
  186    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  187    observe_buffer_font_size_adjustment,
  188};
  189use ui::{
  190    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  191    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  192};
  193use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  194use workspace::{
  195    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  196    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  197    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  198    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  199    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  200    searchable::SearchEvent,
  201};
  202
  203use crate::{
  204    code_context_menus::CompletionsMenuSource,
  205    editor_settings::MultiCursorModifier,
  206    hover_links::{find_url, find_url_from_range},
  207    inlays::{
  208        InlineValueCache,
  209        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  210    },
  211    scroll::{ScrollOffset, ScrollPixelOffset},
  212    selections_collection::resolve_selections_wrapping_blocks,
  213    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  214};
  215
  216pub const FILE_HEADER_HEIGHT: u32 = 2;
  217pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  218const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  219const MAX_LINE_LEN: usize = 1024;
  220const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  221const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  222pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  223#[doc(hidden)]
  224pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  225pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  226
  227pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  230pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  231
  232pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  233pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  234pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  235
  236pub type RenderDiffHunkControlsFn = Arc<
  237    dyn Fn(
  238        u32,
  239        &DiffHunkStatus,
  240        Range<Anchor>,
  241        bool,
  242        Pixels,
  243        &Entity<Editor>,
  244        &mut Window,
  245        &mut App,
  246    ) -> AnyElement,
  247>;
  248
  249enum ReportEditorEvent {
  250    Saved { auto_saved: bool },
  251    EditorOpened,
  252    Closed,
  253}
  254
  255impl ReportEditorEvent {
  256    pub fn event_type(&self) -> &'static str {
  257        match self {
  258            Self::Saved { .. } => "Editor Saved",
  259            Self::EditorOpened => "Editor Opened",
  260            Self::Closed => "Editor Closed",
  261        }
  262    }
  263}
  264
  265pub enum ActiveDebugLine {}
  266pub enum DebugStackFrameLine {}
  267enum DocumentHighlightRead {}
  268enum DocumentHighlightWrite {}
  269enum InputComposition {}
  270pub enum PendingInput {}
  271enum SelectedTextHighlight {}
  272
  273pub enum ConflictsOuter {}
  274pub enum ConflictsOurs {}
  275pub enum ConflictsTheirs {}
  276pub enum ConflictsOursMarker {}
  277pub enum ConflictsTheirsMarker {}
  278
  279#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  280pub enum Navigated {
  281    Yes,
  282    No,
  283}
  284
  285impl Navigated {
  286    pub fn from_bool(yes: bool) -> Navigated {
  287        if yes { Navigated::Yes } else { Navigated::No }
  288    }
  289}
  290
  291#[derive(Debug, Clone, PartialEq, Eq)]
  292enum DisplayDiffHunk {
  293    Folded {
  294        display_row: DisplayRow,
  295    },
  296    Unfolded {
  297        is_created_file: bool,
  298        diff_base_byte_range: Range<usize>,
  299        display_row_range: Range<DisplayRow>,
  300        multi_buffer_range: Range<Anchor>,
  301        status: DiffHunkStatus,
  302    },
  303}
  304
  305pub enum HideMouseCursorOrigin {
  306    TypingAction,
  307    MovementAction,
  308}
  309
  310pub fn init_settings(cx: &mut App) {
  311    EditorSettings::register(cx);
  312}
  313
  314pub fn init(cx: &mut App) {
  315    init_settings(cx);
  316
  317    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  318
  319    workspace::register_project_item::<Editor>(cx);
  320    workspace::FollowableViewRegistry::register::<Editor>(cx);
  321    workspace::register_serializable_item::<Editor>(cx);
  322
  323    cx.observe_new(
  324        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  325            workspace.register_action(Editor::new_file);
  326            workspace.register_action(Editor::new_file_split);
  327            workspace.register_action(Editor::new_file_vertical);
  328            workspace.register_action(Editor::new_file_horizontal);
  329            workspace.register_action(Editor::cancel_language_server_work);
  330            workspace.register_action(Editor::toggle_focus);
  331        },
  332    )
  333    .detach();
  334
  335    cx.on_action(move |_: &workspace::NewFile, cx| {
  336        let app_state = workspace::AppState::global(cx);
  337        if let Some(app_state) = app_state.upgrade() {
  338            workspace::open_new(
  339                Default::default(),
  340                app_state,
  341                cx,
  342                |workspace, window, cx| {
  343                    Editor::new_file(workspace, &Default::default(), window, cx)
  344                },
  345            )
  346            .detach();
  347        }
  348    });
  349    cx.on_action(move |_: &workspace::NewWindow, cx| {
  350        let app_state = workspace::AppState::global(cx);
  351        if let Some(app_state) = app_state.upgrade() {
  352            workspace::open_new(
  353                Default::default(),
  354                app_state,
  355                cx,
  356                |workspace, window, cx| {
  357                    cx.activate(true);
  358                    Editor::new_file(workspace, &Default::default(), window, cx)
  359                },
  360            )
  361            .detach();
  362        }
  363    });
  364}
  365
  366pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  367    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  368}
  369
  370pub trait DiagnosticRenderer {
  371    fn render_group(
  372        &self,
  373        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  374        buffer_id: BufferId,
  375        snapshot: EditorSnapshot,
  376        editor: WeakEntity<Editor>,
  377        cx: &mut App,
  378    ) -> Vec<BlockProperties<Anchor>>;
  379
  380    fn render_hover(
  381        &self,
  382        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  383        range: Range<Point>,
  384        buffer_id: BufferId,
  385        cx: &mut App,
  386    ) -> Option<Entity<markdown::Markdown>>;
  387
  388    fn open_link(
  389        &self,
  390        editor: &mut Editor,
  391        link: SharedString,
  392        window: &mut Window,
  393        cx: &mut Context<Editor>,
  394    );
  395}
  396
  397pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  398
  399impl GlobalDiagnosticRenderer {
  400    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  401        cx.try_global::<Self>().map(|g| g.0.clone())
  402    }
  403}
  404
  405impl gpui::Global for GlobalDiagnosticRenderer {}
  406pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  407    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  408}
  409
  410pub struct SearchWithinRange;
  411
  412trait InvalidationRegion {
  413    fn ranges(&self) -> &[Range<Anchor>];
  414}
  415
  416#[derive(Clone, Debug, PartialEq)]
  417pub enum SelectPhase {
  418    Begin {
  419        position: DisplayPoint,
  420        add: bool,
  421        click_count: usize,
  422    },
  423    BeginColumnar {
  424        position: DisplayPoint,
  425        reset: bool,
  426        mode: ColumnarMode,
  427        goal_column: u32,
  428    },
  429    Extend {
  430        position: DisplayPoint,
  431        click_count: usize,
  432    },
  433    Update {
  434        position: DisplayPoint,
  435        goal_column: u32,
  436        scroll_delta: gpui::Point<f32>,
  437    },
  438    End,
  439}
  440
  441#[derive(Clone, Debug, PartialEq)]
  442pub enum ColumnarMode {
  443    FromMouse,
  444    FromSelection,
  445}
  446
  447#[derive(Clone, Debug)]
  448pub enum SelectMode {
  449    Character,
  450    Word(Range<Anchor>),
  451    Line(Range<Anchor>),
  452    All,
  453}
  454
  455#[derive(Clone, PartialEq, Eq, Debug)]
  456pub enum EditorMode {
  457    SingleLine,
  458    AutoHeight {
  459        min_lines: usize,
  460        max_lines: Option<usize>,
  461    },
  462    Full {
  463        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  464        scale_ui_elements_with_buffer_font_size: bool,
  465        /// When set to `true`, the editor will render a background for the active line.
  466        show_active_line_background: bool,
  467        /// When set to `true`, the editor's height will be determined by its content.
  468        sized_by_content: bool,
  469    },
  470    Minimap {
  471        parent: WeakEntity<Editor>,
  472    },
  473}
  474
  475impl EditorMode {
  476    pub fn full() -> Self {
  477        Self::Full {
  478            scale_ui_elements_with_buffer_font_size: true,
  479            show_active_line_background: true,
  480            sized_by_content: false,
  481        }
  482    }
  483
  484    #[inline]
  485    pub fn is_full(&self) -> bool {
  486        matches!(self, Self::Full { .. })
  487    }
  488
  489    #[inline]
  490    pub fn is_single_line(&self) -> bool {
  491        matches!(self, Self::SingleLine { .. })
  492    }
  493
  494    #[inline]
  495    fn is_minimap(&self) -> bool {
  496        matches!(self, Self::Minimap { .. })
  497    }
  498}
  499
  500#[derive(Copy, Clone, Debug)]
  501pub enum SoftWrap {
  502    /// Prefer not to wrap at all.
  503    ///
  504    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  505    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  506    GitDiff,
  507    /// Prefer a single line generally, unless an overly long line is encountered.
  508    None,
  509    /// Soft wrap lines that exceed the editor width.
  510    EditorWidth,
  511    /// Soft wrap lines at the preferred line length.
  512    Column(u32),
  513    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  514    Bounded(u32),
  515}
  516
  517#[derive(Clone)]
  518pub struct EditorStyle {
  519    pub background: Hsla,
  520    pub border: Hsla,
  521    pub local_player: PlayerColor,
  522    pub text: TextStyle,
  523    pub scrollbar_width: Pixels,
  524    pub syntax: Arc<SyntaxTheme>,
  525    pub status: StatusColors,
  526    pub inlay_hints_style: HighlightStyle,
  527    pub edit_prediction_styles: EditPredictionStyles,
  528    pub unnecessary_code_fade: f32,
  529    pub show_underlines: bool,
  530}
  531
  532impl Default for EditorStyle {
  533    fn default() -> Self {
  534        Self {
  535            background: Hsla::default(),
  536            border: Hsla::default(),
  537            local_player: PlayerColor::default(),
  538            text: TextStyle::default(),
  539            scrollbar_width: Pixels::default(),
  540            syntax: Default::default(),
  541            // HACK: Status colors don't have a real default.
  542            // We should look into removing the status colors from the editor
  543            // style and retrieve them directly from the theme.
  544            status: StatusColors::dark(),
  545            inlay_hints_style: HighlightStyle::default(),
  546            edit_prediction_styles: EditPredictionStyles {
  547                insertion: HighlightStyle::default(),
  548                whitespace: HighlightStyle::default(),
  549            },
  550            unnecessary_code_fade: Default::default(),
  551            show_underlines: true,
  552        }
  553    }
  554}
  555
  556pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  557    let show_background = language_settings::language_settings(None, None, cx)
  558        .inlay_hints
  559        .show_background;
  560
  561    let mut style = cx.theme().syntax().get("hint");
  562
  563    if style.color.is_none() {
  564        style.color = Some(cx.theme().status().hint);
  565    }
  566
  567    if !show_background {
  568        style.background_color = None;
  569        return style;
  570    }
  571
  572    if style.background_color.is_none() {
  573        style.background_color = Some(cx.theme().status().hint_background);
  574    }
  575
  576    style
  577}
  578
  579pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  580    EditPredictionStyles {
  581        insertion: HighlightStyle {
  582            color: Some(cx.theme().status().predictive),
  583            ..HighlightStyle::default()
  584        },
  585        whitespace: HighlightStyle {
  586            background_color: Some(cx.theme().status().created_background),
  587            ..HighlightStyle::default()
  588        },
  589    }
  590}
  591
  592type CompletionId = usize;
  593
  594pub(crate) enum EditDisplayMode {
  595    TabAccept,
  596    DiffPopover,
  597    Inline,
  598}
  599
  600enum EditPrediction {
  601    Edit {
  602        edits: Vec<(Range<Anchor>, String)>,
  603        edit_preview: Option<EditPreview>,
  604        display_mode: EditDisplayMode,
  605        snapshot: BufferSnapshot,
  606    },
  607    /// Move to a specific location in the active editor
  608    MoveWithin {
  609        target: Anchor,
  610        snapshot: BufferSnapshot,
  611    },
  612    /// Move to a specific location in a different editor (not the active one)
  613    MoveOutside {
  614        target: language::Anchor,
  615        snapshot: BufferSnapshot,
  616    },
  617}
  618
  619struct EditPredictionState {
  620    inlay_ids: Vec<InlayId>,
  621    completion: EditPrediction,
  622    completion_id: Option<SharedString>,
  623    invalidation_range: Option<Range<Anchor>>,
  624}
  625
  626enum EditPredictionSettings {
  627    Disabled,
  628    Enabled {
  629        show_in_menu: bool,
  630        preview_requires_modifier: bool,
  631    },
  632}
  633
  634enum EditPredictionHighlight {}
  635
  636#[derive(Debug, Clone)]
  637struct InlineDiagnostic {
  638    message: SharedString,
  639    group_id: usize,
  640    is_primary: bool,
  641    start: Point,
  642    severity: lsp::DiagnosticSeverity,
  643}
  644
  645pub enum MenuEditPredictionsPolicy {
  646    Never,
  647    ByProvider,
  648}
  649
  650pub enum EditPredictionPreview {
  651    /// Modifier is not pressed
  652    Inactive { released_too_fast: bool },
  653    /// Modifier pressed
  654    Active {
  655        since: Instant,
  656        previous_scroll_position: Option<ScrollAnchor>,
  657    },
  658}
  659
  660impl EditPredictionPreview {
  661    pub fn released_too_fast(&self) -> bool {
  662        match self {
  663            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  664            EditPredictionPreview::Active { .. } => false,
  665        }
  666    }
  667
  668    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  669        if let EditPredictionPreview::Active {
  670            previous_scroll_position,
  671            ..
  672        } = self
  673        {
  674            *previous_scroll_position = scroll_position;
  675        }
  676    }
  677}
  678
  679pub struct ContextMenuOptions {
  680    pub min_entries_visible: usize,
  681    pub max_entries_visible: usize,
  682    pub placement: Option<ContextMenuPlacement>,
  683}
  684
  685#[derive(Debug, Clone, PartialEq, Eq)]
  686pub enum ContextMenuPlacement {
  687    Above,
  688    Below,
  689}
  690
  691#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  692struct EditorActionId(usize);
  693
  694impl EditorActionId {
  695    pub fn post_inc(&mut self) -> Self {
  696        let answer = self.0;
  697
  698        *self = Self(answer + 1);
  699
  700        Self(answer)
  701    }
  702}
  703
  704// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  705// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  706
  707type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  708type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  709
  710#[derive(Default)]
  711struct ScrollbarMarkerState {
  712    scrollbar_size: Size<Pixels>,
  713    dirty: bool,
  714    markers: Arc<[PaintQuad]>,
  715    pending_refresh: Option<Task<Result<()>>>,
  716}
  717
  718impl ScrollbarMarkerState {
  719    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  720        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  721    }
  722}
  723
  724#[derive(Clone, Copy, PartialEq, Eq)]
  725pub enum MinimapVisibility {
  726    Disabled,
  727    Enabled {
  728        /// The configuration currently present in the users settings.
  729        setting_configuration: bool,
  730        /// Whether to override the currently set visibility from the users setting.
  731        toggle_override: bool,
  732    },
  733}
  734
  735impl MinimapVisibility {
  736    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  737        if mode.is_full() {
  738            Self::Enabled {
  739                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  740                toggle_override: false,
  741            }
  742        } else {
  743            Self::Disabled
  744        }
  745    }
  746
  747    fn hidden(&self) -> Self {
  748        match *self {
  749            Self::Enabled {
  750                setting_configuration,
  751                ..
  752            } => Self::Enabled {
  753                setting_configuration,
  754                toggle_override: setting_configuration,
  755            },
  756            Self::Disabled => Self::Disabled,
  757        }
  758    }
  759
  760    fn disabled(&self) -> bool {
  761        matches!(*self, Self::Disabled)
  762    }
  763
  764    fn settings_visibility(&self) -> bool {
  765        match *self {
  766            Self::Enabled {
  767                setting_configuration,
  768                ..
  769            } => setting_configuration,
  770            _ => false,
  771        }
  772    }
  773
  774    fn visible(&self) -> bool {
  775        match *self {
  776            Self::Enabled {
  777                setting_configuration,
  778                toggle_override,
  779            } => setting_configuration ^ toggle_override,
  780            _ => false,
  781        }
  782    }
  783
  784    fn toggle_visibility(&self) -> Self {
  785        match *self {
  786            Self::Enabled {
  787                toggle_override,
  788                setting_configuration,
  789            } => Self::Enabled {
  790                setting_configuration,
  791                toggle_override: !toggle_override,
  792            },
  793            Self::Disabled => Self::Disabled,
  794        }
  795    }
  796}
  797
  798#[derive(Clone, Debug)]
  799struct RunnableTasks {
  800    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  801    offset: multi_buffer::Anchor,
  802    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  803    column: u32,
  804    // Values of all named captures, including those starting with '_'
  805    extra_variables: HashMap<String, String>,
  806    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  807    context_range: Range<BufferOffset>,
  808}
  809
  810impl RunnableTasks {
  811    fn resolve<'a>(
  812        &'a self,
  813        cx: &'a task::TaskContext,
  814    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  815        self.templates.iter().filter_map(|(kind, template)| {
  816            template
  817                .resolve_task(&kind.to_id_base(), cx)
  818                .map(|task| (kind.clone(), task))
  819        })
  820    }
  821}
  822
  823#[derive(Clone)]
  824pub struct ResolvedTasks {
  825    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  826    position: Anchor,
  827}
  828
  829#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  830struct BufferOffset(usize);
  831
  832/// Addons allow storing per-editor state in other crates (e.g. Vim)
  833pub trait Addon: 'static {
  834    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  835
  836    fn render_buffer_header_controls(
  837        &self,
  838        _: &ExcerptInfo,
  839        _: &Window,
  840        _: &App,
  841    ) -> Option<AnyElement> {
  842        None
  843    }
  844
  845    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  846        None
  847    }
  848
  849    fn to_any(&self) -> &dyn std::any::Any;
  850
  851    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  852        None
  853    }
  854}
  855
  856struct ChangeLocation {
  857    current: Option<Vec<Anchor>>,
  858    original: Vec<Anchor>,
  859}
  860impl ChangeLocation {
  861    fn locations(&self) -> &[Anchor] {
  862        self.current.as_ref().unwrap_or(&self.original)
  863    }
  864}
  865
  866/// A set of caret positions, registered when the editor was edited.
  867pub struct ChangeList {
  868    changes: Vec<ChangeLocation>,
  869    /// Currently "selected" change.
  870    position: Option<usize>,
  871}
  872
  873impl ChangeList {
  874    pub fn new() -> Self {
  875        Self {
  876            changes: Vec::new(),
  877            position: None,
  878        }
  879    }
  880
  881    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  882    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  883    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  884        if self.changes.is_empty() {
  885            return None;
  886        }
  887
  888        let prev = self.position.unwrap_or(self.changes.len());
  889        let next = if direction == Direction::Prev {
  890            prev.saturating_sub(count)
  891        } else {
  892            (prev + count).min(self.changes.len() - 1)
  893        };
  894        self.position = Some(next);
  895        self.changes.get(next).map(|change| change.locations())
  896    }
  897
  898    /// Adds a new change to the list, resetting the change list position.
  899    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  900        self.position.take();
  901        if let Some(last) = self.changes.last_mut()
  902            && group
  903        {
  904            last.current = Some(new_positions)
  905        } else {
  906            self.changes.push(ChangeLocation {
  907                original: new_positions,
  908                current: None,
  909            });
  910        }
  911    }
  912
  913    pub fn last(&self) -> Option<&[Anchor]> {
  914        self.changes.last().map(|change| change.locations())
  915    }
  916
  917    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  918        self.changes.last().map(|change| change.original.as_slice())
  919    }
  920
  921    pub fn invert_last_group(&mut self) {
  922        if let Some(last) = self.changes.last_mut()
  923            && let Some(current) = last.current.as_mut()
  924        {
  925            mem::swap(&mut last.original, current);
  926        }
  927    }
  928}
  929
  930#[derive(Clone)]
  931struct InlineBlamePopoverState {
  932    scroll_handle: ScrollHandle,
  933    commit_message: Option<ParsedCommitMessage>,
  934    markdown: Entity<Markdown>,
  935}
  936
  937struct InlineBlamePopover {
  938    position: gpui::Point<Pixels>,
  939    hide_task: Option<Task<()>>,
  940    popover_bounds: Option<Bounds<Pixels>>,
  941    popover_state: InlineBlamePopoverState,
  942    keyboard_grace: bool,
  943}
  944
  945enum SelectionDragState {
  946    /// State when no drag related activity is detected.
  947    None,
  948    /// State when the mouse is down on a selection that is about to be dragged.
  949    ReadyToDrag {
  950        selection: Selection<Anchor>,
  951        click_position: gpui::Point<Pixels>,
  952        mouse_down_time: Instant,
  953    },
  954    /// State when the mouse is dragging the selection in the editor.
  955    Dragging {
  956        selection: Selection<Anchor>,
  957        drop_cursor: Selection<Anchor>,
  958        hide_drop_cursor: bool,
  959    },
  960}
  961
  962enum ColumnarSelectionState {
  963    FromMouse {
  964        selection_tail: Anchor,
  965        display_point: Option<DisplayPoint>,
  966    },
  967    FromSelection {
  968        selection_tail: Anchor,
  969    },
  970}
  971
  972/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  973/// a breakpoint on them.
  974#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  975struct PhantomBreakpointIndicator {
  976    display_row: DisplayRow,
  977    /// There's a small debounce between hovering over the line and showing the indicator.
  978    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  979    is_active: bool,
  980    collides_with_existing_breakpoint: bool,
  981}
  982
  983/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  984///
  985/// See the [module level documentation](self) for more information.
  986pub struct Editor {
  987    focus_handle: FocusHandle,
  988    last_focused_descendant: Option<WeakFocusHandle>,
  989    /// The text buffer being edited
  990    buffer: Entity<MultiBuffer>,
  991    /// Map of how text in the buffer should be displayed.
  992    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  993    pub display_map: Entity<DisplayMap>,
  994    placeholder_display_map: Option<Entity<DisplayMap>>,
  995    pub selections: SelectionsCollection,
  996    pub scroll_manager: ScrollManager,
  997    /// When inline assist editors are linked, they all render cursors because
  998    /// typing enters text into each of them, even the ones that aren't focused.
  999    pub(crate) show_cursor_when_unfocused: bool,
 1000    columnar_selection_state: Option<ColumnarSelectionState>,
 1001    add_selections_state: Option<AddSelectionsState>,
 1002    select_next_state: Option<SelectNextState>,
 1003    select_prev_state: Option<SelectNextState>,
 1004    selection_history: SelectionHistory,
 1005    defer_selection_effects: bool,
 1006    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1007    autoclose_regions: Vec<AutocloseRegion>,
 1008    snippet_stack: InvalidationStack<SnippetState>,
 1009    select_syntax_node_history: SelectSyntaxNodeHistory,
 1010    ime_transaction: Option<TransactionId>,
 1011    pub diagnostics_max_severity: DiagnosticSeverity,
 1012    active_diagnostics: ActiveDiagnostic,
 1013    show_inline_diagnostics: bool,
 1014    inline_diagnostics_update: Task<()>,
 1015    inline_diagnostics_enabled: bool,
 1016    diagnostics_enabled: bool,
 1017    word_completions_enabled: bool,
 1018    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1019    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1020    hard_wrap: Option<usize>,
 1021    project: Option<Entity<Project>>,
 1022    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1023    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1024    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1025    blink_manager: Entity<BlinkManager>,
 1026    show_cursor_names: bool,
 1027    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1028    pub show_local_selections: bool,
 1029    mode: EditorMode,
 1030    show_breadcrumbs: bool,
 1031    show_gutter: bool,
 1032    show_scrollbars: ScrollbarAxes,
 1033    minimap_visibility: MinimapVisibility,
 1034    offset_content: bool,
 1035    disable_expand_excerpt_buttons: bool,
 1036    show_line_numbers: Option<bool>,
 1037    use_relative_line_numbers: Option<bool>,
 1038    show_git_diff_gutter: Option<bool>,
 1039    show_code_actions: Option<bool>,
 1040    show_runnables: Option<bool>,
 1041    show_breakpoints: Option<bool>,
 1042    show_wrap_guides: Option<bool>,
 1043    show_indent_guides: Option<bool>,
 1044    highlight_order: usize,
 1045    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1046    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1047    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1048    scrollbar_marker_state: ScrollbarMarkerState,
 1049    active_indent_guides_state: ActiveIndentGuidesState,
 1050    nav_history: Option<ItemNavHistory>,
 1051    context_menu: RefCell<Option<CodeContextMenu>>,
 1052    context_menu_options: Option<ContextMenuOptions>,
 1053    mouse_context_menu: Option<MouseContextMenu>,
 1054    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1055    inline_blame_popover: Option<InlineBlamePopover>,
 1056    inline_blame_popover_show_task: Option<Task<()>>,
 1057    signature_help_state: SignatureHelpState,
 1058    auto_signature_help: Option<bool>,
 1059    find_all_references_task_sources: Vec<Anchor>,
 1060    next_completion_id: CompletionId,
 1061    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1062    code_actions_task: Option<Task<Result<()>>>,
 1063    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1064    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1065    document_highlights_task: Option<Task<()>>,
 1066    linked_editing_range_task: Option<Task<Option<()>>>,
 1067    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1068    pending_rename: Option<RenameState>,
 1069    searchable: bool,
 1070    cursor_shape: CursorShape,
 1071    current_line_highlight: Option<CurrentLineHighlight>,
 1072    collapse_matches: bool,
 1073    autoindent_mode: Option<AutoindentMode>,
 1074    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1075    input_enabled: bool,
 1076    use_modal_editing: bool,
 1077    read_only: bool,
 1078    leader_id: Option<CollaboratorId>,
 1079    remote_id: Option<ViewId>,
 1080    pub hover_state: HoverState,
 1081    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1082    gutter_hovered: bool,
 1083    hovered_link_state: Option<HoveredLinkState>,
 1084    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1085    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1086    active_edit_prediction: Option<EditPredictionState>,
 1087    /// Used to prevent flickering as the user types while the menu is open
 1088    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1089    edit_prediction_settings: EditPredictionSettings,
 1090    edit_predictions_hidden_for_vim_mode: bool,
 1091    show_edit_predictions_override: Option<bool>,
 1092    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1093    edit_prediction_preview: EditPredictionPreview,
 1094    edit_prediction_indent_conflict: bool,
 1095    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1096    next_inlay_id: usize,
 1097    next_color_inlay_id: usize,
 1098    _subscriptions: Vec<Subscription>,
 1099    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1100    gutter_dimensions: GutterDimensions,
 1101    style: Option<EditorStyle>,
 1102    text_style_refinement: Option<TextStyleRefinement>,
 1103    next_editor_action_id: EditorActionId,
 1104    editor_actions: Rc<
 1105        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1106    >,
 1107    use_autoclose: bool,
 1108    use_auto_surround: bool,
 1109    auto_replace_emoji_shortcode: bool,
 1110    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1111    show_git_blame_gutter: bool,
 1112    show_git_blame_inline: bool,
 1113    show_git_blame_inline_delay_task: Option<Task<()>>,
 1114    git_blame_inline_enabled: bool,
 1115    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1116    serialize_dirty_buffers: bool,
 1117    show_selection_menu: Option<bool>,
 1118    blame: Option<Entity<GitBlame>>,
 1119    blame_subscription: Option<Subscription>,
 1120    custom_context_menu: Option<
 1121        Box<
 1122            dyn 'static
 1123                + Fn(
 1124                    &mut Self,
 1125                    DisplayPoint,
 1126                    &mut Window,
 1127                    &mut Context<Self>,
 1128                ) -> Option<Entity<ui::ContextMenu>>,
 1129        >,
 1130    >,
 1131    last_bounds: Option<Bounds<Pixels>>,
 1132    last_position_map: Option<Rc<PositionMap>>,
 1133    expect_bounds_change: Option<Bounds<Pixels>>,
 1134    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1135    tasks_update_task: Option<Task<()>>,
 1136    breakpoint_store: Option<Entity<BreakpointStore>>,
 1137    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1138    hovered_diff_hunk_row: Option<DisplayRow>,
 1139    pull_diagnostics_task: Task<()>,
 1140    in_project_search: bool,
 1141    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1142    breadcrumb_header: Option<String>,
 1143    focused_block: Option<FocusedBlock>,
 1144    next_scroll_position: NextScrollCursorCenterTopBottom,
 1145    addons: HashMap<TypeId, Box<dyn Addon>>,
 1146    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1147    load_diff_task: Option<Shared<Task<()>>>,
 1148    /// Whether we are temporarily displaying a diff other than git's
 1149    temporary_diff_override: bool,
 1150    selection_mark_mode: bool,
 1151    toggle_fold_multiple_buffers: Task<()>,
 1152    _scroll_cursor_center_top_bottom_task: Task<()>,
 1153    serialize_selections: Task<()>,
 1154    serialize_folds: Task<()>,
 1155    mouse_cursor_hidden: bool,
 1156    minimap: Option<Entity<Self>>,
 1157    hide_mouse_mode: HideMouseMode,
 1158    pub change_list: ChangeList,
 1159    inline_value_cache: InlineValueCache,
 1160    selection_drag_state: SelectionDragState,
 1161    colors: Option<LspColorData>,
 1162    post_scroll_update: Task<()>,
 1163    refresh_colors_task: Task<()>,
 1164    inlay_hints: Option<LspInlayHintData>,
 1165    folding_newlines: Task<()>,
 1166    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1167}
 1168
 1169fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1170    if debounce_ms > 0 {
 1171        Some(Duration::from_millis(debounce_ms))
 1172    } else {
 1173        None
 1174    }
 1175}
 1176
 1177#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1178enum NextScrollCursorCenterTopBottom {
 1179    #[default]
 1180    Center,
 1181    Top,
 1182    Bottom,
 1183}
 1184
 1185impl NextScrollCursorCenterTopBottom {
 1186    fn next(&self) -> Self {
 1187        match self {
 1188            Self::Center => Self::Top,
 1189            Self::Top => Self::Bottom,
 1190            Self::Bottom => Self::Center,
 1191        }
 1192    }
 1193}
 1194
 1195#[derive(Clone)]
 1196pub struct EditorSnapshot {
 1197    pub mode: EditorMode,
 1198    show_gutter: bool,
 1199    show_line_numbers: Option<bool>,
 1200    show_git_diff_gutter: Option<bool>,
 1201    show_code_actions: Option<bool>,
 1202    show_runnables: Option<bool>,
 1203    show_breakpoints: Option<bool>,
 1204    git_blame_gutter_max_author_length: Option<usize>,
 1205    pub display_snapshot: DisplaySnapshot,
 1206    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1207    is_focused: bool,
 1208    scroll_anchor: ScrollAnchor,
 1209    ongoing_scroll: OngoingScroll,
 1210    current_line_highlight: CurrentLineHighlight,
 1211    gutter_hovered: bool,
 1212}
 1213
 1214#[derive(Default, Debug, Clone, Copy)]
 1215pub struct GutterDimensions {
 1216    pub left_padding: Pixels,
 1217    pub right_padding: Pixels,
 1218    pub width: Pixels,
 1219    pub margin: Pixels,
 1220    pub git_blame_entries_width: Option<Pixels>,
 1221}
 1222
 1223impl GutterDimensions {
 1224    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1225        Self {
 1226            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1227            ..Default::default()
 1228        }
 1229    }
 1230
 1231    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1232        -cx.text_system().descent(font_id, font_size)
 1233    }
 1234    /// The full width of the space taken up by the gutter.
 1235    pub fn full_width(&self) -> Pixels {
 1236        self.margin + self.width
 1237    }
 1238
 1239    /// The width of the space reserved for the fold indicators,
 1240    /// use alongside 'justify_end' and `gutter_width` to
 1241    /// right align content with the line numbers
 1242    pub fn fold_area_width(&self) -> Pixels {
 1243        self.margin + self.right_padding
 1244    }
 1245}
 1246
 1247struct CharacterDimensions {
 1248    em_width: Pixels,
 1249    em_advance: Pixels,
 1250    line_height: Pixels,
 1251}
 1252
 1253#[derive(Debug)]
 1254pub struct RemoteSelection {
 1255    pub replica_id: ReplicaId,
 1256    pub selection: Selection<Anchor>,
 1257    pub cursor_shape: CursorShape,
 1258    pub collaborator_id: CollaboratorId,
 1259    pub line_mode: bool,
 1260    pub user_name: Option<SharedString>,
 1261    pub color: PlayerColor,
 1262}
 1263
 1264#[derive(Clone, Debug)]
 1265struct SelectionHistoryEntry {
 1266    selections: Arc<[Selection<Anchor>]>,
 1267    select_next_state: Option<SelectNextState>,
 1268    select_prev_state: Option<SelectNextState>,
 1269    add_selections_state: Option<AddSelectionsState>,
 1270}
 1271
 1272#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1273enum SelectionHistoryMode {
 1274    Normal,
 1275    Undoing,
 1276    Redoing,
 1277    Skipping,
 1278}
 1279
 1280#[derive(Clone, PartialEq, Eq, Hash)]
 1281struct HoveredCursor {
 1282    replica_id: ReplicaId,
 1283    selection_id: usize,
 1284}
 1285
 1286impl Default for SelectionHistoryMode {
 1287    fn default() -> Self {
 1288        Self::Normal
 1289    }
 1290}
 1291
 1292#[derive(Debug)]
 1293/// SelectionEffects controls the side-effects of updating the selection.
 1294///
 1295/// The default behaviour does "what you mostly want":
 1296/// - it pushes to the nav history if the cursor moved by >10 lines
 1297/// - it re-triggers completion requests
 1298/// - it scrolls to fit
 1299///
 1300/// You might want to modify these behaviours. For example when doing a "jump"
 1301/// like go to definition, we always want to add to nav history; but when scrolling
 1302/// in vim mode we never do.
 1303///
 1304/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1305/// move.
 1306#[derive(Clone)]
 1307pub struct SelectionEffects {
 1308    nav_history: Option<bool>,
 1309    completions: bool,
 1310    scroll: Option<Autoscroll>,
 1311}
 1312
 1313impl Default for SelectionEffects {
 1314    fn default() -> Self {
 1315        Self {
 1316            nav_history: None,
 1317            completions: true,
 1318            scroll: Some(Autoscroll::fit()),
 1319        }
 1320    }
 1321}
 1322impl SelectionEffects {
 1323    pub fn scroll(scroll: Autoscroll) -> Self {
 1324        Self {
 1325            scroll: Some(scroll),
 1326            ..Default::default()
 1327        }
 1328    }
 1329
 1330    pub fn no_scroll() -> Self {
 1331        Self {
 1332            scroll: None,
 1333            ..Default::default()
 1334        }
 1335    }
 1336
 1337    pub fn completions(self, completions: bool) -> Self {
 1338        Self {
 1339            completions,
 1340            ..self
 1341        }
 1342    }
 1343
 1344    pub fn nav_history(self, nav_history: bool) -> Self {
 1345        Self {
 1346            nav_history: Some(nav_history),
 1347            ..self
 1348        }
 1349    }
 1350}
 1351
 1352struct DeferredSelectionEffectsState {
 1353    changed: bool,
 1354    effects: SelectionEffects,
 1355    old_cursor_position: Anchor,
 1356    history_entry: SelectionHistoryEntry,
 1357}
 1358
 1359#[derive(Default)]
 1360struct SelectionHistory {
 1361    #[allow(clippy::type_complexity)]
 1362    selections_by_transaction:
 1363        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1364    mode: SelectionHistoryMode,
 1365    undo_stack: VecDeque<SelectionHistoryEntry>,
 1366    redo_stack: VecDeque<SelectionHistoryEntry>,
 1367}
 1368
 1369impl SelectionHistory {
 1370    #[track_caller]
 1371    fn insert_transaction(
 1372        &mut self,
 1373        transaction_id: TransactionId,
 1374        selections: Arc<[Selection<Anchor>]>,
 1375    ) {
 1376        if selections.is_empty() {
 1377            log::error!(
 1378                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1379                std::panic::Location::caller()
 1380            );
 1381            return;
 1382        }
 1383        self.selections_by_transaction
 1384            .insert(transaction_id, (selections, None));
 1385    }
 1386
 1387    #[allow(clippy::type_complexity)]
 1388    fn transaction(
 1389        &self,
 1390        transaction_id: TransactionId,
 1391    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1392        self.selections_by_transaction.get(&transaction_id)
 1393    }
 1394
 1395    #[allow(clippy::type_complexity)]
 1396    fn transaction_mut(
 1397        &mut self,
 1398        transaction_id: TransactionId,
 1399    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1400        self.selections_by_transaction.get_mut(&transaction_id)
 1401    }
 1402
 1403    fn push(&mut self, entry: SelectionHistoryEntry) {
 1404        if !entry.selections.is_empty() {
 1405            match self.mode {
 1406                SelectionHistoryMode::Normal => {
 1407                    self.push_undo(entry);
 1408                    self.redo_stack.clear();
 1409                }
 1410                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1411                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1412                SelectionHistoryMode::Skipping => {}
 1413            }
 1414        }
 1415    }
 1416
 1417    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1418        if self
 1419            .undo_stack
 1420            .back()
 1421            .is_none_or(|e| e.selections != entry.selections)
 1422        {
 1423            self.undo_stack.push_back(entry);
 1424            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1425                self.undo_stack.pop_front();
 1426            }
 1427        }
 1428    }
 1429
 1430    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1431        if self
 1432            .redo_stack
 1433            .back()
 1434            .is_none_or(|e| e.selections != entry.selections)
 1435        {
 1436            self.redo_stack.push_back(entry);
 1437            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1438                self.redo_stack.pop_front();
 1439            }
 1440        }
 1441    }
 1442}
 1443
 1444#[derive(Clone, Copy)]
 1445pub struct RowHighlightOptions {
 1446    pub autoscroll: bool,
 1447    pub include_gutter: bool,
 1448}
 1449
 1450impl Default for RowHighlightOptions {
 1451    fn default() -> Self {
 1452        Self {
 1453            autoscroll: Default::default(),
 1454            include_gutter: true,
 1455        }
 1456    }
 1457}
 1458
 1459struct RowHighlight {
 1460    index: usize,
 1461    range: Range<Anchor>,
 1462    color: Hsla,
 1463    options: RowHighlightOptions,
 1464    type_id: TypeId,
 1465}
 1466
 1467#[derive(Clone, Debug)]
 1468struct AddSelectionsState {
 1469    groups: Vec<AddSelectionsGroup>,
 1470}
 1471
 1472#[derive(Clone, Debug)]
 1473struct AddSelectionsGroup {
 1474    above: bool,
 1475    stack: Vec<usize>,
 1476}
 1477
 1478#[derive(Clone)]
 1479struct SelectNextState {
 1480    query: AhoCorasick,
 1481    wordwise: bool,
 1482    done: bool,
 1483}
 1484
 1485impl std::fmt::Debug for SelectNextState {
 1486    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1487        f.debug_struct(std::any::type_name::<Self>())
 1488            .field("wordwise", &self.wordwise)
 1489            .field("done", &self.done)
 1490            .finish()
 1491    }
 1492}
 1493
 1494#[derive(Debug)]
 1495struct AutocloseRegion {
 1496    selection_id: usize,
 1497    range: Range<Anchor>,
 1498    pair: BracketPair,
 1499}
 1500
 1501#[derive(Debug)]
 1502struct SnippetState {
 1503    ranges: Vec<Vec<Range<Anchor>>>,
 1504    active_index: usize,
 1505    choices: Vec<Option<Vec<String>>>,
 1506}
 1507
 1508#[doc(hidden)]
 1509pub struct RenameState {
 1510    pub range: Range<Anchor>,
 1511    pub old_name: Arc<str>,
 1512    pub editor: Entity<Editor>,
 1513    block_id: CustomBlockId,
 1514}
 1515
 1516struct InvalidationStack<T>(Vec<T>);
 1517
 1518struct RegisteredEditPredictionProvider {
 1519    provider: Arc<dyn EditPredictionProviderHandle>,
 1520    _subscription: Subscription,
 1521}
 1522
 1523#[derive(Debug, PartialEq, Eq)]
 1524pub struct ActiveDiagnosticGroup {
 1525    pub active_range: Range<Anchor>,
 1526    pub active_message: String,
 1527    pub group_id: usize,
 1528    pub blocks: HashSet<CustomBlockId>,
 1529}
 1530
 1531#[derive(Debug, PartialEq, Eq)]
 1532
 1533pub(crate) enum ActiveDiagnostic {
 1534    None,
 1535    All,
 1536    Group(ActiveDiagnosticGroup),
 1537}
 1538
 1539#[derive(Serialize, Deserialize, Clone, Debug)]
 1540pub struct ClipboardSelection {
 1541    /// The number of bytes in this selection.
 1542    pub len: usize,
 1543    /// Whether this was a full-line selection.
 1544    pub is_entire_line: bool,
 1545    /// The indentation of the first line when this content was originally copied.
 1546    pub first_line_indent: u32,
 1547}
 1548
 1549// selections, scroll behavior, was newest selection reversed
 1550type SelectSyntaxNodeHistoryState = (
 1551    Box<[Selection<usize>]>,
 1552    SelectSyntaxNodeScrollBehavior,
 1553    bool,
 1554);
 1555
 1556#[derive(Default)]
 1557struct SelectSyntaxNodeHistory {
 1558    stack: Vec<SelectSyntaxNodeHistoryState>,
 1559    // disable temporarily to allow changing selections without losing the stack
 1560    pub disable_clearing: bool,
 1561}
 1562
 1563impl SelectSyntaxNodeHistory {
 1564    pub fn try_clear(&mut self) {
 1565        if !self.disable_clearing {
 1566            self.stack.clear();
 1567        }
 1568    }
 1569
 1570    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1571        self.stack.push(selection);
 1572    }
 1573
 1574    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1575        self.stack.pop()
 1576    }
 1577}
 1578
 1579enum SelectSyntaxNodeScrollBehavior {
 1580    CursorTop,
 1581    FitSelection,
 1582    CursorBottom,
 1583}
 1584
 1585#[derive(Debug)]
 1586pub(crate) struct NavigationData {
 1587    cursor_anchor: Anchor,
 1588    cursor_position: Point,
 1589    scroll_anchor: ScrollAnchor,
 1590    scroll_top_row: u32,
 1591}
 1592
 1593#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1594pub enum GotoDefinitionKind {
 1595    Symbol,
 1596    Declaration,
 1597    Type,
 1598    Implementation,
 1599}
 1600
 1601pub enum FormatTarget {
 1602    Buffers(HashSet<Entity<Buffer>>),
 1603    Ranges(Vec<Range<MultiBufferPoint>>),
 1604}
 1605
 1606pub(crate) struct FocusedBlock {
 1607    id: BlockId,
 1608    focus_handle: WeakFocusHandle,
 1609}
 1610
 1611#[derive(Clone)]
 1612enum JumpData {
 1613    MultiBufferRow {
 1614        row: MultiBufferRow,
 1615        line_offset_from_top: u32,
 1616    },
 1617    MultiBufferPoint {
 1618        excerpt_id: ExcerptId,
 1619        position: Point,
 1620        anchor: text::Anchor,
 1621        line_offset_from_top: u32,
 1622    },
 1623}
 1624
 1625pub enum MultibufferSelectionMode {
 1626    First,
 1627    All,
 1628}
 1629
 1630#[derive(Clone, Copy, Debug, Default)]
 1631pub struct RewrapOptions {
 1632    pub override_language_settings: bool,
 1633    pub preserve_existing_whitespace: bool,
 1634}
 1635
 1636impl Editor {
 1637    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1638        let buffer = cx.new(|cx| Buffer::local("", cx));
 1639        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1640        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1641    }
 1642
 1643    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1644        let buffer = cx.new(|cx| Buffer::local("", cx));
 1645        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1646        Self::new(EditorMode::full(), buffer, None, window, cx)
 1647    }
 1648
 1649    pub fn auto_height(
 1650        min_lines: usize,
 1651        max_lines: usize,
 1652        window: &mut Window,
 1653        cx: &mut Context<Self>,
 1654    ) -> Self {
 1655        let buffer = cx.new(|cx| Buffer::local("", cx));
 1656        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1657        Self::new(
 1658            EditorMode::AutoHeight {
 1659                min_lines,
 1660                max_lines: Some(max_lines),
 1661            },
 1662            buffer,
 1663            None,
 1664            window,
 1665            cx,
 1666        )
 1667    }
 1668
 1669    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1670    /// The editor grows as tall as needed to fit its content.
 1671    pub fn auto_height_unbounded(
 1672        min_lines: usize,
 1673        window: &mut Window,
 1674        cx: &mut Context<Self>,
 1675    ) -> Self {
 1676        let buffer = cx.new(|cx| Buffer::local("", cx));
 1677        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1678        Self::new(
 1679            EditorMode::AutoHeight {
 1680                min_lines,
 1681                max_lines: None,
 1682            },
 1683            buffer,
 1684            None,
 1685            window,
 1686            cx,
 1687        )
 1688    }
 1689
 1690    pub fn for_buffer(
 1691        buffer: Entity<Buffer>,
 1692        project: Option<Entity<Project>>,
 1693        window: &mut Window,
 1694        cx: &mut Context<Self>,
 1695    ) -> Self {
 1696        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1697        Self::new(EditorMode::full(), buffer, project, window, cx)
 1698    }
 1699
 1700    pub fn for_multibuffer(
 1701        buffer: Entity<MultiBuffer>,
 1702        project: Option<Entity<Project>>,
 1703        window: &mut Window,
 1704        cx: &mut Context<Self>,
 1705    ) -> Self {
 1706        Self::new(EditorMode::full(), buffer, project, window, cx)
 1707    }
 1708
 1709    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1710        let mut clone = Self::new(
 1711            self.mode.clone(),
 1712            self.buffer.clone(),
 1713            self.project.clone(),
 1714            window,
 1715            cx,
 1716        );
 1717        self.display_map.update(cx, |display_map, cx| {
 1718            let snapshot = display_map.snapshot(cx);
 1719            clone.display_map.update(cx, |display_map, cx| {
 1720                display_map.set_state(&snapshot, cx);
 1721            });
 1722        });
 1723        clone.folds_did_change(cx);
 1724        clone.selections.clone_state(&self.selections);
 1725        clone.scroll_manager.clone_state(&self.scroll_manager);
 1726        clone.searchable = self.searchable;
 1727        clone.read_only = self.read_only;
 1728        clone
 1729    }
 1730
 1731    pub fn new(
 1732        mode: EditorMode,
 1733        buffer: Entity<MultiBuffer>,
 1734        project: Option<Entity<Project>>,
 1735        window: &mut Window,
 1736        cx: &mut Context<Self>,
 1737    ) -> Self {
 1738        Editor::new_internal(mode, buffer, project, None, window, cx)
 1739    }
 1740
 1741    fn new_internal(
 1742        mode: EditorMode,
 1743        multi_buffer: Entity<MultiBuffer>,
 1744        project: Option<Entity<Project>>,
 1745        display_map: Option<Entity<DisplayMap>>,
 1746        window: &mut Window,
 1747        cx: &mut Context<Self>,
 1748    ) -> Self {
 1749        debug_assert!(
 1750            display_map.is_none() || mode.is_minimap(),
 1751            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1752        );
 1753
 1754        let full_mode = mode.is_full();
 1755        let is_minimap = mode.is_minimap();
 1756        let diagnostics_max_severity = if full_mode {
 1757            EditorSettings::get_global(cx)
 1758                .diagnostics_max_severity
 1759                .unwrap_or(DiagnosticSeverity::Hint)
 1760        } else {
 1761            DiagnosticSeverity::Off
 1762        };
 1763        let style = window.text_style();
 1764        let font_size = style.font_size.to_pixels(window.rem_size());
 1765        let editor = cx.entity().downgrade();
 1766        let fold_placeholder = FoldPlaceholder {
 1767            constrain_width: false,
 1768            render: Arc::new(move |fold_id, fold_range, cx| {
 1769                let editor = editor.clone();
 1770                div()
 1771                    .id(fold_id)
 1772                    .bg(cx.theme().colors().ghost_element_background)
 1773                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1774                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1775                    .rounded_xs()
 1776                    .size_full()
 1777                    .cursor_pointer()
 1778                    .child("")
 1779                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1780                    .on_click(move |_, _window, cx| {
 1781                        editor
 1782                            .update(cx, |editor, cx| {
 1783                                editor.unfold_ranges(
 1784                                    &[fold_range.start..fold_range.end],
 1785                                    true,
 1786                                    false,
 1787                                    cx,
 1788                                );
 1789                                cx.stop_propagation();
 1790                            })
 1791                            .ok();
 1792                    })
 1793                    .into_any()
 1794            }),
 1795            merge_adjacent: true,
 1796            ..FoldPlaceholder::default()
 1797        };
 1798        let display_map = display_map.unwrap_or_else(|| {
 1799            cx.new(|cx| {
 1800                DisplayMap::new(
 1801                    multi_buffer.clone(),
 1802                    style.font(),
 1803                    font_size,
 1804                    None,
 1805                    FILE_HEADER_HEIGHT,
 1806                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1807                    fold_placeholder,
 1808                    diagnostics_max_severity,
 1809                    cx,
 1810                )
 1811            })
 1812        });
 1813
 1814        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1815
 1816        let blink_manager = cx.new(|cx| {
 1817            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1818            if is_minimap {
 1819                blink_manager.disable(cx);
 1820            }
 1821            blink_manager
 1822        });
 1823
 1824        let soft_wrap_mode_override =
 1825            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1826
 1827        let mut project_subscriptions = Vec::new();
 1828        if full_mode && let Some(project) = project.as_ref() {
 1829            project_subscriptions.push(cx.subscribe_in(
 1830                project,
 1831                window,
 1832                |editor, _, event, window, cx| match event {
 1833                    project::Event::RefreshCodeLens => {
 1834                        // we always query lens with actions, without storing them, always refreshing them
 1835                    }
 1836                    project::Event::RefreshInlayHints {
 1837                        server_id,
 1838                        request_id,
 1839                    } => {
 1840                        editor.refresh_inlay_hints(
 1841                            InlayHintRefreshReason::RefreshRequested {
 1842                                server_id: *server_id,
 1843                                request_id: *request_id,
 1844                            },
 1845                            cx,
 1846                        );
 1847                    }
 1848                    project::Event::LanguageServerRemoved(..) => {
 1849                        if editor.tasks_update_task.is_none() {
 1850                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1851                        }
 1852                        editor.registered_buffers.clear();
 1853                        editor.register_visible_buffers(cx);
 1854                    }
 1855                    project::Event::LanguageServerAdded(..) => {
 1856                        if editor.tasks_update_task.is_none() {
 1857                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1858                        }
 1859                    }
 1860                    project::Event::SnippetEdit(id, snippet_edits) => {
 1861                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1862                            let focus_handle = editor.focus_handle(cx);
 1863                            if focus_handle.is_focused(window) {
 1864                                let snapshot = buffer.read(cx).snapshot();
 1865                                for (range, snippet) in snippet_edits {
 1866                                    let editor_range =
 1867                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1868                                    editor
 1869                                        .insert_snippet(
 1870                                            &[editor_range],
 1871                                            snippet.clone(),
 1872                                            window,
 1873                                            cx,
 1874                                        )
 1875                                        .ok();
 1876                                }
 1877                            }
 1878                        }
 1879                    }
 1880                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1881                        let buffer_id = *buffer_id;
 1882                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1883                            editor.register_buffer(buffer_id, cx);
 1884                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1885                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1886                            refresh_linked_ranges(editor, window, cx);
 1887                            editor.refresh_code_actions(window, cx);
 1888                            editor.refresh_document_highlights(cx);
 1889                        }
 1890                    }
 1891
 1892                    project::Event::EntryRenamed(transaction) => {
 1893                        let Some(workspace) = editor.workspace() else {
 1894                            return;
 1895                        };
 1896                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1897                        else {
 1898                            return;
 1899                        };
 1900                        if active_editor.entity_id() == cx.entity_id() {
 1901                            let edited_buffers_already_open = {
 1902                                let other_editors: Vec<Entity<Editor>> = workspace
 1903                                    .read(cx)
 1904                                    .panes()
 1905                                    .iter()
 1906                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1907                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1908                                    .collect();
 1909
 1910                                transaction.0.keys().all(|buffer| {
 1911                                    other_editors.iter().any(|editor| {
 1912                                        let multi_buffer = editor.read(cx).buffer();
 1913                                        multi_buffer.read(cx).is_singleton()
 1914                                            && multi_buffer.read(cx).as_singleton().map_or(
 1915                                                false,
 1916                                                |singleton| {
 1917                                                    singleton.entity_id() == buffer.entity_id()
 1918                                                },
 1919                                            )
 1920                                    })
 1921                                })
 1922                            };
 1923
 1924                            if !edited_buffers_already_open {
 1925                                let workspace = workspace.downgrade();
 1926                                let transaction = transaction.clone();
 1927                                cx.defer_in(window, move |_, window, cx| {
 1928                                    cx.spawn_in(window, async move |editor, cx| {
 1929                                        Self::open_project_transaction(
 1930                                            &editor,
 1931                                            workspace,
 1932                                            transaction,
 1933                                            "Rename".to_string(),
 1934                                            cx,
 1935                                        )
 1936                                        .await
 1937                                        .ok()
 1938                                    })
 1939                                    .detach();
 1940                                });
 1941                            }
 1942                        }
 1943                    }
 1944
 1945                    _ => {}
 1946                },
 1947            ));
 1948            if let Some(task_inventory) = project
 1949                .read(cx)
 1950                .task_store()
 1951                .read(cx)
 1952                .task_inventory()
 1953                .cloned()
 1954            {
 1955                project_subscriptions.push(cx.observe_in(
 1956                    &task_inventory,
 1957                    window,
 1958                    |editor, _, window, cx| {
 1959                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1960                    },
 1961                ));
 1962            };
 1963
 1964            project_subscriptions.push(cx.subscribe_in(
 1965                &project.read(cx).breakpoint_store(),
 1966                window,
 1967                |editor, _, event, window, cx| match event {
 1968                    BreakpointStoreEvent::ClearDebugLines => {
 1969                        editor.clear_row_highlights::<ActiveDebugLine>();
 1970                        editor.refresh_inline_values(cx);
 1971                    }
 1972                    BreakpointStoreEvent::SetDebugLine => {
 1973                        if editor.go_to_active_debug_line(window, cx) {
 1974                            cx.stop_propagation();
 1975                        }
 1976
 1977                        editor.refresh_inline_values(cx);
 1978                    }
 1979                    _ => {}
 1980                },
 1981            ));
 1982            let git_store = project.read(cx).git_store().clone();
 1983            let project = project.clone();
 1984            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1985                if let GitStoreEvent::RepositoryAdded = event {
 1986                    this.load_diff_task = Some(
 1987                        update_uncommitted_diff_for_buffer(
 1988                            cx.entity(),
 1989                            &project,
 1990                            this.buffer.read(cx).all_buffers(),
 1991                            this.buffer.clone(),
 1992                            cx,
 1993                        )
 1994                        .shared(),
 1995                    );
 1996                }
 1997            }));
 1998        }
 1999
 2000        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2001
 2002        let inlay_hint_settings =
 2003            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2004        let focus_handle = cx.focus_handle();
 2005        if !is_minimap {
 2006            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2007                .detach();
 2008            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2009                .detach();
 2010            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2011                .detach();
 2012            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2013                .detach();
 2014            cx.observe_pending_input(window, Self::observe_pending_input)
 2015                .detach();
 2016        }
 2017
 2018        let show_indent_guides =
 2019            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2020                Some(false)
 2021            } else {
 2022                None
 2023            };
 2024
 2025        let breakpoint_store = match (&mode, project.as_ref()) {
 2026            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2027            _ => None,
 2028        };
 2029
 2030        let mut code_action_providers = Vec::new();
 2031        let mut load_uncommitted_diff = None;
 2032        if let Some(project) = project.clone() {
 2033            load_uncommitted_diff = Some(
 2034                update_uncommitted_diff_for_buffer(
 2035                    cx.entity(),
 2036                    &project,
 2037                    multi_buffer.read(cx).all_buffers(),
 2038                    multi_buffer.clone(),
 2039                    cx,
 2040                )
 2041                .shared(),
 2042            );
 2043            code_action_providers.push(Rc::new(project) as Rc<_>);
 2044        }
 2045
 2046        let mut editor = Self {
 2047            focus_handle,
 2048            show_cursor_when_unfocused: false,
 2049            last_focused_descendant: None,
 2050            buffer: multi_buffer.clone(),
 2051            display_map: display_map.clone(),
 2052            placeholder_display_map: None,
 2053            selections,
 2054            scroll_manager: ScrollManager::new(cx),
 2055            columnar_selection_state: None,
 2056            add_selections_state: None,
 2057            select_next_state: None,
 2058            select_prev_state: None,
 2059            selection_history: SelectionHistory::default(),
 2060            defer_selection_effects: false,
 2061            deferred_selection_effects_state: None,
 2062            autoclose_regions: Vec::new(),
 2063            snippet_stack: InvalidationStack::default(),
 2064            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2065            ime_transaction: None,
 2066            active_diagnostics: ActiveDiagnostic::None,
 2067            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2068            inline_diagnostics_update: Task::ready(()),
 2069            inline_diagnostics: Vec::new(),
 2070            soft_wrap_mode_override,
 2071            diagnostics_max_severity,
 2072            hard_wrap: None,
 2073            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2074            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2075            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2076            project,
 2077            blink_manager: blink_manager.clone(),
 2078            show_local_selections: true,
 2079            show_scrollbars: ScrollbarAxes {
 2080                horizontal: full_mode,
 2081                vertical: full_mode,
 2082            },
 2083            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2084            offset_content: !matches!(mode, EditorMode::SingleLine),
 2085            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2086            show_gutter: full_mode,
 2087            show_line_numbers: (!full_mode).then_some(false),
 2088            use_relative_line_numbers: None,
 2089            disable_expand_excerpt_buttons: !full_mode,
 2090            show_git_diff_gutter: None,
 2091            show_code_actions: None,
 2092            show_runnables: None,
 2093            show_breakpoints: None,
 2094            show_wrap_guides: None,
 2095            show_indent_guides,
 2096            highlight_order: 0,
 2097            highlighted_rows: HashMap::default(),
 2098            background_highlights: HashMap::default(),
 2099            gutter_highlights: HashMap::default(),
 2100            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2101            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2102            nav_history: None,
 2103            context_menu: RefCell::new(None),
 2104            context_menu_options: None,
 2105            mouse_context_menu: None,
 2106            completion_tasks: Vec::new(),
 2107            inline_blame_popover: None,
 2108            inline_blame_popover_show_task: None,
 2109            signature_help_state: SignatureHelpState::default(),
 2110            auto_signature_help: None,
 2111            find_all_references_task_sources: Vec::new(),
 2112            next_completion_id: 0,
 2113            next_inlay_id: 0,
 2114            code_action_providers,
 2115            available_code_actions: None,
 2116            code_actions_task: None,
 2117            quick_selection_highlight_task: None,
 2118            debounced_selection_highlight_task: None,
 2119            document_highlights_task: None,
 2120            linked_editing_range_task: None,
 2121            pending_rename: None,
 2122            searchable: !is_minimap,
 2123            cursor_shape: EditorSettings::get_global(cx)
 2124                .cursor_shape
 2125                .unwrap_or_default(),
 2126            current_line_highlight: None,
 2127            autoindent_mode: Some(AutoindentMode::EachLine),
 2128            collapse_matches: false,
 2129            workspace: None,
 2130            input_enabled: !is_minimap,
 2131            use_modal_editing: full_mode,
 2132            read_only: is_minimap,
 2133            use_autoclose: true,
 2134            use_auto_surround: true,
 2135            auto_replace_emoji_shortcode: false,
 2136            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2137            leader_id: None,
 2138            remote_id: None,
 2139            hover_state: HoverState::default(),
 2140            pending_mouse_down: None,
 2141            hovered_link_state: None,
 2142            edit_prediction_provider: None,
 2143            active_edit_prediction: None,
 2144            stale_edit_prediction_in_menu: None,
 2145            edit_prediction_preview: EditPredictionPreview::Inactive {
 2146                released_too_fast: false,
 2147            },
 2148            inline_diagnostics_enabled: full_mode,
 2149            diagnostics_enabled: full_mode,
 2150            word_completions_enabled: full_mode,
 2151            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2152            gutter_hovered: false,
 2153            pixel_position_of_newest_cursor: None,
 2154            last_bounds: None,
 2155            last_position_map: None,
 2156            expect_bounds_change: None,
 2157            gutter_dimensions: GutterDimensions::default(),
 2158            style: None,
 2159            show_cursor_names: false,
 2160            hovered_cursors: HashMap::default(),
 2161            next_editor_action_id: EditorActionId::default(),
 2162            editor_actions: Rc::default(),
 2163            edit_predictions_hidden_for_vim_mode: false,
 2164            show_edit_predictions_override: None,
 2165            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2166            edit_prediction_settings: EditPredictionSettings::Disabled,
 2167            edit_prediction_indent_conflict: false,
 2168            edit_prediction_requires_modifier_in_indent_conflict: true,
 2169            custom_context_menu: None,
 2170            show_git_blame_gutter: false,
 2171            show_git_blame_inline: false,
 2172            show_selection_menu: None,
 2173            show_git_blame_inline_delay_task: None,
 2174            git_blame_inline_enabled: full_mode
 2175                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2176            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2177            serialize_dirty_buffers: !is_minimap
 2178                && ProjectSettings::get_global(cx)
 2179                    .session
 2180                    .restore_unsaved_buffers,
 2181            blame: None,
 2182            blame_subscription: None,
 2183            tasks: BTreeMap::default(),
 2184
 2185            breakpoint_store,
 2186            gutter_breakpoint_indicator: (None, None),
 2187            hovered_diff_hunk_row: None,
 2188            _subscriptions: (!is_minimap)
 2189                .then(|| {
 2190                    vec![
 2191                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2192                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2193                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2194                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2195                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2196                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2197                        cx.observe_window_activation(window, |editor, window, cx| {
 2198                            let active = window.is_window_active();
 2199                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2200                                if active {
 2201                                    blink_manager.enable(cx);
 2202                                } else {
 2203                                    blink_manager.disable(cx);
 2204                                }
 2205                            });
 2206                            if active {
 2207                                editor.show_mouse_cursor(cx);
 2208                            }
 2209                        }),
 2210                    ]
 2211                })
 2212                .unwrap_or_default(),
 2213            tasks_update_task: None,
 2214            pull_diagnostics_task: Task::ready(()),
 2215            colors: None,
 2216            refresh_colors_task: Task::ready(()),
 2217            inlay_hints: None,
 2218            next_color_inlay_id: 0,
 2219            post_scroll_update: Task::ready(()),
 2220            linked_edit_ranges: Default::default(),
 2221            in_project_search: false,
 2222            previous_search_ranges: None,
 2223            breadcrumb_header: None,
 2224            focused_block: None,
 2225            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2226            addons: HashMap::default(),
 2227            registered_buffers: HashMap::default(),
 2228            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2229            selection_mark_mode: false,
 2230            toggle_fold_multiple_buffers: Task::ready(()),
 2231            serialize_selections: Task::ready(()),
 2232            serialize_folds: Task::ready(()),
 2233            text_style_refinement: None,
 2234            load_diff_task: load_uncommitted_diff,
 2235            temporary_diff_override: false,
 2236            mouse_cursor_hidden: false,
 2237            minimap: None,
 2238            hide_mouse_mode: EditorSettings::get_global(cx)
 2239                .hide_mouse
 2240                .unwrap_or_default(),
 2241            change_list: ChangeList::new(),
 2242            mode,
 2243            selection_drag_state: SelectionDragState::None,
 2244            folding_newlines: Task::ready(()),
 2245            lookup_key: None,
 2246        };
 2247
 2248        if is_minimap {
 2249            return editor;
 2250        }
 2251
 2252        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2253            editor
 2254                ._subscriptions
 2255                .push(cx.observe(breakpoints, |_, _, cx| {
 2256                    cx.notify();
 2257                }));
 2258        }
 2259        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2260        editor._subscriptions.extend(project_subscriptions);
 2261
 2262        editor._subscriptions.push(cx.subscribe_in(
 2263            &cx.entity(),
 2264            window,
 2265            |editor, _, e: &EditorEvent, window, cx| match e {
 2266                EditorEvent::ScrollPositionChanged { local, .. } => {
 2267                    if *local {
 2268                        let new_anchor = editor.scroll_manager.anchor();
 2269                        let snapshot = editor.snapshot(window, cx);
 2270                        editor.update_restoration_data(cx, move |data| {
 2271                            data.scroll_position = (
 2272                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2273                                new_anchor.offset,
 2274                            );
 2275                        });
 2276                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2277                        editor.inline_blame_popover.take();
 2278                    }
 2279                }
 2280                EditorEvent::Edited { .. } => {
 2281                    if !vim_enabled(cx) {
 2282                        let display_map = editor.display_snapshot(cx);
 2283                        let selections = editor.selections.all_adjusted_display(&display_map);
 2284                        let pop_state = editor
 2285                            .change_list
 2286                            .last()
 2287                            .map(|previous| {
 2288                                previous.len() == selections.len()
 2289                                    && previous.iter().enumerate().all(|(ix, p)| {
 2290                                        p.to_display_point(&display_map).row()
 2291                                            == selections[ix].head().row()
 2292                                    })
 2293                            })
 2294                            .unwrap_or(false);
 2295                        let new_positions = selections
 2296                            .into_iter()
 2297                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2298                            .collect();
 2299                        editor
 2300                            .change_list
 2301                            .push_to_change_list(pop_state, new_positions);
 2302                    }
 2303                }
 2304                _ => (),
 2305            },
 2306        ));
 2307
 2308        if let Some(dap_store) = editor
 2309            .project
 2310            .as_ref()
 2311            .map(|project| project.read(cx).dap_store())
 2312        {
 2313            let weak_editor = cx.weak_entity();
 2314
 2315            editor
 2316                ._subscriptions
 2317                .push(
 2318                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2319                        let session_entity = cx.entity();
 2320                        weak_editor
 2321                            .update(cx, |editor, cx| {
 2322                                editor._subscriptions.push(
 2323                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2324                                );
 2325                            })
 2326                            .ok();
 2327                    }),
 2328                );
 2329
 2330            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2331                editor
 2332                    ._subscriptions
 2333                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2334            }
 2335        }
 2336
 2337        // skip adding the initial selection to selection history
 2338        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2339        editor.end_selection(window, cx);
 2340        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2341
 2342        editor.scroll_manager.show_scrollbars(window, cx);
 2343        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2344
 2345        if full_mode {
 2346            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2347            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2348
 2349            if editor.git_blame_inline_enabled {
 2350                editor.start_git_blame_inline(false, window, cx);
 2351            }
 2352
 2353            editor.go_to_active_debug_line(window, cx);
 2354
 2355            editor.minimap =
 2356                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2357            editor.colors = Some(LspColorData::new(cx));
 2358            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2359
 2360            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2361                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2362            }
 2363            editor.update_lsp_data(None, window, cx);
 2364            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2365        }
 2366
 2367        editor
 2368    }
 2369
 2370    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2371        self.selections.display_map(cx)
 2372    }
 2373
 2374    pub fn deploy_mouse_context_menu(
 2375        &mut self,
 2376        position: gpui::Point<Pixels>,
 2377        context_menu: Entity<ContextMenu>,
 2378        window: &mut Window,
 2379        cx: &mut Context<Self>,
 2380    ) {
 2381        self.mouse_context_menu = Some(MouseContextMenu::new(
 2382            self,
 2383            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2384            context_menu,
 2385            window,
 2386            cx,
 2387        ));
 2388    }
 2389
 2390    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2391        self.mouse_context_menu
 2392            .as_ref()
 2393            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2394    }
 2395
 2396    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2397        if self
 2398            .selections
 2399            .pending_anchor()
 2400            .is_some_and(|pending_selection| {
 2401                let snapshot = self.buffer().read(cx).snapshot(cx);
 2402                pending_selection.range().includes(range, &snapshot)
 2403            })
 2404        {
 2405            return true;
 2406        }
 2407
 2408        self.selections
 2409            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2410            .into_iter()
 2411            .any(|selection| {
 2412                // This is needed to cover a corner case, if we just check for an existing
 2413                // selection in the fold range, having a cursor at the start of the fold
 2414                // marks it as selected. Non-empty selections don't cause this.
 2415                let length = selection.end - selection.start;
 2416                length > 0
 2417            })
 2418    }
 2419
 2420    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2421        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2422    }
 2423
 2424    fn key_context_internal(
 2425        &self,
 2426        has_active_edit_prediction: bool,
 2427        window: &mut Window,
 2428        cx: &mut App,
 2429    ) -> KeyContext {
 2430        let mut key_context = KeyContext::new_with_defaults();
 2431        key_context.add("Editor");
 2432        let mode = match self.mode {
 2433            EditorMode::SingleLine => "single_line",
 2434            EditorMode::AutoHeight { .. } => "auto_height",
 2435            EditorMode::Minimap { .. } => "minimap",
 2436            EditorMode::Full { .. } => "full",
 2437        };
 2438
 2439        if EditorSettings::jupyter_enabled(cx) {
 2440            key_context.add("jupyter");
 2441        }
 2442
 2443        key_context.set("mode", mode);
 2444        if self.pending_rename.is_some() {
 2445            key_context.add("renaming");
 2446        }
 2447
 2448        match self.context_menu.borrow().as_ref() {
 2449            Some(CodeContextMenu::Completions(menu)) => {
 2450                if menu.visible() {
 2451                    key_context.add("menu");
 2452                    key_context.add("showing_completions");
 2453                }
 2454            }
 2455            Some(CodeContextMenu::CodeActions(menu)) => {
 2456                if menu.visible() {
 2457                    key_context.add("menu");
 2458                    key_context.add("showing_code_actions")
 2459                }
 2460            }
 2461            None => {}
 2462        }
 2463
 2464        if self.signature_help_state.has_multiple_signatures() {
 2465            key_context.add("showing_signature_help");
 2466        }
 2467
 2468        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2469        if !self.focus_handle(cx).contains_focused(window, cx)
 2470            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2471        {
 2472            for addon in self.addons.values() {
 2473                addon.extend_key_context(&mut key_context, cx)
 2474            }
 2475        }
 2476
 2477        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2478            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2479                Some(
 2480                    file.full_path(cx)
 2481                        .extension()?
 2482                        .to_string_lossy()
 2483                        .into_owned(),
 2484                )
 2485            }) {
 2486                key_context.set("extension", extension);
 2487            }
 2488        } else {
 2489            key_context.add("multibuffer");
 2490        }
 2491
 2492        if has_active_edit_prediction {
 2493            if self.edit_prediction_in_conflict() {
 2494                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2495            } else {
 2496                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2497                key_context.add("copilot_suggestion");
 2498            }
 2499        }
 2500
 2501        if self.selection_mark_mode {
 2502            key_context.add("selection_mode");
 2503        }
 2504
 2505        let disjoint = self.selections.disjoint_anchors();
 2506        let snapshot = self.snapshot(window, cx);
 2507        let snapshot = snapshot.buffer_snapshot();
 2508        if self.mode == EditorMode::SingleLine
 2509            && let [selection] = disjoint
 2510            && selection.start == selection.end
 2511            && selection.end.to_offset(snapshot) == snapshot.len()
 2512        {
 2513            key_context.add("end_of_input");
 2514        }
 2515
 2516        key_context
 2517    }
 2518
 2519    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2520        self.last_bounds.as_ref()
 2521    }
 2522
 2523    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2524        if self.mouse_cursor_hidden {
 2525            self.mouse_cursor_hidden = false;
 2526            cx.notify();
 2527        }
 2528    }
 2529
 2530    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2531        let hide_mouse_cursor = match origin {
 2532            HideMouseCursorOrigin::TypingAction => {
 2533                matches!(
 2534                    self.hide_mouse_mode,
 2535                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2536                )
 2537            }
 2538            HideMouseCursorOrigin::MovementAction => {
 2539                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2540            }
 2541        };
 2542        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2543            self.mouse_cursor_hidden = hide_mouse_cursor;
 2544            cx.notify();
 2545        }
 2546    }
 2547
 2548    pub fn edit_prediction_in_conflict(&self) -> bool {
 2549        if !self.show_edit_predictions_in_menu() {
 2550            return false;
 2551        }
 2552
 2553        let showing_completions = self
 2554            .context_menu
 2555            .borrow()
 2556            .as_ref()
 2557            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2558
 2559        showing_completions
 2560            || self.edit_prediction_requires_modifier()
 2561            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2562            // bindings to insert tab characters.
 2563            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2564    }
 2565
 2566    pub fn accept_edit_prediction_keybind(
 2567        &self,
 2568        accept_partial: bool,
 2569        window: &mut Window,
 2570        cx: &mut App,
 2571    ) -> AcceptEditPredictionBinding {
 2572        let key_context = self.key_context_internal(true, window, cx);
 2573        let in_conflict = self.edit_prediction_in_conflict();
 2574
 2575        let bindings = if accept_partial {
 2576            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2577        } else {
 2578            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2579        };
 2580
 2581        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2582        // just the first one.
 2583        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2584            !in_conflict
 2585                || binding
 2586                    .keystrokes()
 2587                    .first()
 2588                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2589        }))
 2590    }
 2591
 2592    pub fn new_file(
 2593        workspace: &mut Workspace,
 2594        _: &workspace::NewFile,
 2595        window: &mut Window,
 2596        cx: &mut Context<Workspace>,
 2597    ) {
 2598        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2599            "Failed to create buffer",
 2600            window,
 2601            cx,
 2602            |e, _, _| match e.error_code() {
 2603                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2604                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2605                e.error_tag("required").unwrap_or("the latest version")
 2606            )),
 2607                _ => None,
 2608            },
 2609        );
 2610    }
 2611
 2612    pub fn new_in_workspace(
 2613        workspace: &mut Workspace,
 2614        window: &mut Window,
 2615        cx: &mut Context<Workspace>,
 2616    ) -> Task<Result<Entity<Editor>>> {
 2617        let project = workspace.project().clone();
 2618        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2619
 2620        cx.spawn_in(window, async move |workspace, cx| {
 2621            let buffer = create.await?;
 2622            workspace.update_in(cx, |workspace, window, cx| {
 2623                let editor =
 2624                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2625                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2626                editor
 2627            })
 2628        })
 2629    }
 2630
 2631    fn new_file_vertical(
 2632        workspace: &mut Workspace,
 2633        _: &workspace::NewFileSplitVertical,
 2634        window: &mut Window,
 2635        cx: &mut Context<Workspace>,
 2636    ) {
 2637        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2638    }
 2639
 2640    fn new_file_horizontal(
 2641        workspace: &mut Workspace,
 2642        _: &workspace::NewFileSplitHorizontal,
 2643        window: &mut Window,
 2644        cx: &mut Context<Workspace>,
 2645    ) {
 2646        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2647    }
 2648
 2649    fn new_file_split(
 2650        workspace: &mut Workspace,
 2651        action: &workspace::NewFileSplit,
 2652        window: &mut Window,
 2653        cx: &mut Context<Workspace>,
 2654    ) {
 2655        Self::new_file_in_direction(workspace, action.0, window, cx)
 2656    }
 2657
 2658    fn new_file_in_direction(
 2659        workspace: &mut Workspace,
 2660        direction: SplitDirection,
 2661        window: &mut Window,
 2662        cx: &mut Context<Workspace>,
 2663    ) {
 2664        let project = workspace.project().clone();
 2665        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2666
 2667        cx.spawn_in(window, async move |workspace, cx| {
 2668            let buffer = create.await?;
 2669            workspace.update_in(cx, move |workspace, window, cx| {
 2670                workspace.split_item(
 2671                    direction,
 2672                    Box::new(
 2673                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2674                    ),
 2675                    window,
 2676                    cx,
 2677                )
 2678            })?;
 2679            anyhow::Ok(())
 2680        })
 2681        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2682            match e.error_code() {
 2683                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2684                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2685                e.error_tag("required").unwrap_or("the latest version")
 2686            )),
 2687                _ => None,
 2688            }
 2689        });
 2690    }
 2691
 2692    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2693        self.leader_id
 2694    }
 2695
 2696    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2697        &self.buffer
 2698    }
 2699
 2700    pub fn project(&self) -> Option<&Entity<Project>> {
 2701        self.project.as_ref()
 2702    }
 2703
 2704    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2705        self.workspace.as_ref()?.0.upgrade()
 2706    }
 2707
 2708    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2709        self.buffer().read(cx).title(cx)
 2710    }
 2711
 2712    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2713        let git_blame_gutter_max_author_length = self
 2714            .render_git_blame_gutter(cx)
 2715            .then(|| {
 2716                if let Some(blame) = self.blame.as_ref() {
 2717                    let max_author_length =
 2718                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2719                    Some(max_author_length)
 2720                } else {
 2721                    None
 2722                }
 2723            })
 2724            .flatten();
 2725
 2726        EditorSnapshot {
 2727            mode: self.mode.clone(),
 2728            show_gutter: self.show_gutter,
 2729            show_line_numbers: self.show_line_numbers,
 2730            show_git_diff_gutter: self.show_git_diff_gutter,
 2731            show_code_actions: self.show_code_actions,
 2732            show_runnables: self.show_runnables,
 2733            show_breakpoints: self.show_breakpoints,
 2734            git_blame_gutter_max_author_length,
 2735            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2736            placeholder_display_snapshot: self
 2737                .placeholder_display_map
 2738                .as_ref()
 2739                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2740            scroll_anchor: self.scroll_manager.anchor(),
 2741            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2742            is_focused: self.focus_handle.is_focused(window),
 2743            current_line_highlight: self
 2744                .current_line_highlight
 2745                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2746            gutter_hovered: self.gutter_hovered,
 2747        }
 2748    }
 2749
 2750    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2751        self.buffer.read(cx).language_at(point, cx)
 2752    }
 2753
 2754    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2755        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2756    }
 2757
 2758    pub fn active_excerpt(
 2759        &self,
 2760        cx: &App,
 2761    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2762        self.buffer
 2763            .read(cx)
 2764            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2765    }
 2766
 2767    pub fn mode(&self) -> &EditorMode {
 2768        &self.mode
 2769    }
 2770
 2771    pub fn set_mode(&mut self, mode: EditorMode) {
 2772        self.mode = mode;
 2773    }
 2774
 2775    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2776        self.collaboration_hub.as_deref()
 2777    }
 2778
 2779    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2780        self.collaboration_hub = Some(hub);
 2781    }
 2782
 2783    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2784        self.in_project_search = in_project_search;
 2785    }
 2786
 2787    pub fn set_custom_context_menu(
 2788        &mut self,
 2789        f: impl 'static
 2790        + Fn(
 2791            &mut Self,
 2792            DisplayPoint,
 2793            &mut Window,
 2794            &mut Context<Self>,
 2795        ) -> Option<Entity<ui::ContextMenu>>,
 2796    ) {
 2797        self.custom_context_menu = Some(Box::new(f))
 2798    }
 2799
 2800    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2801        self.completion_provider = provider;
 2802    }
 2803
 2804    #[cfg(any(test, feature = "test-support"))]
 2805    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2806        self.completion_provider.clone()
 2807    }
 2808
 2809    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2810        self.semantics_provider.clone()
 2811    }
 2812
 2813    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2814        self.semantics_provider = provider;
 2815    }
 2816
 2817    pub fn set_edit_prediction_provider<T>(
 2818        &mut self,
 2819        provider: Option<Entity<T>>,
 2820        window: &mut Window,
 2821        cx: &mut Context<Self>,
 2822    ) where
 2823        T: EditPredictionProvider,
 2824    {
 2825        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2826            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2827                if this.focus_handle.is_focused(window) {
 2828                    this.update_visible_edit_prediction(window, cx);
 2829                }
 2830            }),
 2831            provider: Arc::new(provider),
 2832        });
 2833        self.update_edit_prediction_settings(cx);
 2834        self.refresh_edit_prediction(false, false, window, cx);
 2835    }
 2836
 2837    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2838        self.placeholder_display_map
 2839            .as_ref()
 2840            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2841    }
 2842
 2843    pub fn set_placeholder_text(
 2844        &mut self,
 2845        placeholder_text: &str,
 2846        window: &mut Window,
 2847        cx: &mut Context<Self>,
 2848    ) {
 2849        let multibuffer = cx
 2850            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2851
 2852        let style = window.text_style();
 2853
 2854        self.placeholder_display_map = Some(cx.new(|cx| {
 2855            DisplayMap::new(
 2856                multibuffer,
 2857                style.font(),
 2858                style.font_size.to_pixels(window.rem_size()),
 2859                None,
 2860                FILE_HEADER_HEIGHT,
 2861                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2862                Default::default(),
 2863                DiagnosticSeverity::Off,
 2864                cx,
 2865            )
 2866        }));
 2867        cx.notify();
 2868    }
 2869
 2870    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2871        self.cursor_shape = cursor_shape;
 2872
 2873        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2874        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2875
 2876        cx.notify();
 2877    }
 2878
 2879    pub fn set_current_line_highlight(
 2880        &mut self,
 2881        current_line_highlight: Option<CurrentLineHighlight>,
 2882    ) {
 2883        self.current_line_highlight = current_line_highlight;
 2884    }
 2885
 2886    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2887        self.collapse_matches = collapse_matches;
 2888    }
 2889
 2890    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2891        if self.collapse_matches {
 2892            return range.start..range.start;
 2893        }
 2894        range.clone()
 2895    }
 2896
 2897    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2898        if self.display_map.read(cx).clip_at_line_ends != clip {
 2899            self.display_map
 2900                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2901        }
 2902    }
 2903
 2904    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2905        self.input_enabled = input_enabled;
 2906    }
 2907
 2908    pub fn set_edit_predictions_hidden_for_vim_mode(
 2909        &mut self,
 2910        hidden: bool,
 2911        window: &mut Window,
 2912        cx: &mut Context<Self>,
 2913    ) {
 2914        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2915            self.edit_predictions_hidden_for_vim_mode = hidden;
 2916            if hidden {
 2917                self.update_visible_edit_prediction(window, cx);
 2918            } else {
 2919                self.refresh_edit_prediction(true, false, window, cx);
 2920            }
 2921        }
 2922    }
 2923
 2924    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2925        self.menu_edit_predictions_policy = value;
 2926    }
 2927
 2928    pub fn set_autoindent(&mut self, autoindent: bool) {
 2929        if autoindent {
 2930            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2931        } else {
 2932            self.autoindent_mode = None;
 2933        }
 2934    }
 2935
 2936    pub fn read_only(&self, cx: &App) -> bool {
 2937        self.read_only || self.buffer.read(cx).read_only()
 2938    }
 2939
 2940    pub fn set_read_only(&mut self, read_only: bool) {
 2941        self.read_only = read_only;
 2942    }
 2943
 2944    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2945        self.use_autoclose = autoclose;
 2946    }
 2947
 2948    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2949        self.use_auto_surround = auto_surround;
 2950    }
 2951
 2952    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2953        self.auto_replace_emoji_shortcode = auto_replace;
 2954    }
 2955
 2956    pub fn toggle_edit_predictions(
 2957        &mut self,
 2958        _: &ToggleEditPrediction,
 2959        window: &mut Window,
 2960        cx: &mut Context<Self>,
 2961    ) {
 2962        if self.show_edit_predictions_override.is_some() {
 2963            self.set_show_edit_predictions(None, window, cx);
 2964        } else {
 2965            let show_edit_predictions = !self.edit_predictions_enabled();
 2966            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2967        }
 2968    }
 2969
 2970    pub fn set_show_edit_predictions(
 2971        &mut self,
 2972        show_edit_predictions: Option<bool>,
 2973        window: &mut Window,
 2974        cx: &mut Context<Self>,
 2975    ) {
 2976        self.show_edit_predictions_override = show_edit_predictions;
 2977        self.update_edit_prediction_settings(cx);
 2978
 2979        if let Some(false) = show_edit_predictions {
 2980            self.discard_edit_prediction(false, cx);
 2981        } else {
 2982            self.refresh_edit_prediction(false, true, window, cx);
 2983        }
 2984    }
 2985
 2986    fn edit_predictions_disabled_in_scope(
 2987        &self,
 2988        buffer: &Entity<Buffer>,
 2989        buffer_position: language::Anchor,
 2990        cx: &App,
 2991    ) -> bool {
 2992        let snapshot = buffer.read(cx).snapshot();
 2993        let settings = snapshot.settings_at(buffer_position, cx);
 2994
 2995        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2996            return false;
 2997        };
 2998
 2999        scope.override_name().is_some_and(|scope_name| {
 3000            settings
 3001                .edit_predictions_disabled_in
 3002                .iter()
 3003                .any(|s| s == scope_name)
 3004        })
 3005    }
 3006
 3007    pub fn set_use_modal_editing(&mut self, to: bool) {
 3008        self.use_modal_editing = to;
 3009    }
 3010
 3011    pub fn use_modal_editing(&self) -> bool {
 3012        self.use_modal_editing
 3013    }
 3014
 3015    fn selections_did_change(
 3016        &mut self,
 3017        local: bool,
 3018        old_cursor_position: &Anchor,
 3019        effects: SelectionEffects,
 3020        window: &mut Window,
 3021        cx: &mut Context<Self>,
 3022    ) {
 3023        window.invalidate_character_coordinates();
 3024
 3025        // Copy selections to primary selection buffer
 3026        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3027        if local {
 3028            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3029            let buffer_handle = self.buffer.read(cx).read(cx);
 3030
 3031            let mut text = String::new();
 3032            for (index, selection) in selections.iter().enumerate() {
 3033                let text_for_selection = buffer_handle
 3034                    .text_for_range(selection.start..selection.end)
 3035                    .collect::<String>();
 3036
 3037                text.push_str(&text_for_selection);
 3038                if index != selections.len() - 1 {
 3039                    text.push('\n');
 3040                }
 3041            }
 3042
 3043            if !text.is_empty() {
 3044                cx.write_to_primary(ClipboardItem::new_string(text));
 3045            }
 3046        }
 3047
 3048        let selection_anchors = self.selections.disjoint_anchors_arc();
 3049
 3050        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3051            self.buffer.update(cx, |buffer, cx| {
 3052                buffer.set_active_selections(
 3053                    &selection_anchors,
 3054                    self.selections.line_mode(),
 3055                    self.cursor_shape,
 3056                    cx,
 3057                )
 3058            });
 3059        }
 3060        let display_map = self
 3061            .display_map
 3062            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3063        let buffer = display_map.buffer_snapshot();
 3064        if self.selections.count() == 1 {
 3065            self.add_selections_state = None;
 3066        }
 3067        self.select_next_state = None;
 3068        self.select_prev_state = None;
 3069        self.select_syntax_node_history.try_clear();
 3070        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3071        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3072        self.take_rename(false, window, cx);
 3073
 3074        let newest_selection = self.selections.newest_anchor();
 3075        let new_cursor_position = newest_selection.head();
 3076        let selection_start = newest_selection.start;
 3077
 3078        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3079            self.push_to_nav_history(
 3080                *old_cursor_position,
 3081                Some(new_cursor_position.to_point(buffer)),
 3082                false,
 3083                effects.nav_history == Some(true),
 3084                cx,
 3085            );
 3086        }
 3087
 3088        if local {
 3089            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3090                self.register_buffer(buffer_id, cx);
 3091            }
 3092
 3093            let mut context_menu = self.context_menu.borrow_mut();
 3094            let completion_menu = match context_menu.as_ref() {
 3095                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3096                Some(CodeContextMenu::CodeActions(_)) => {
 3097                    *context_menu = None;
 3098                    None
 3099                }
 3100                None => None,
 3101            };
 3102            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3103            drop(context_menu);
 3104
 3105            if effects.completions
 3106                && let Some(completion_position) = completion_position
 3107            {
 3108                let start_offset = selection_start.to_offset(buffer);
 3109                let position_matches = start_offset == completion_position.to_offset(buffer);
 3110                let continue_showing = if position_matches {
 3111                    if self.snippet_stack.is_empty() {
 3112                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3113                            == Some(CharKind::Word)
 3114                    } else {
 3115                        // Snippet choices can be shown even when the cursor is in whitespace.
 3116                        // Dismissing the menu with actions like backspace is handled by
 3117                        // invalidation regions.
 3118                        true
 3119                    }
 3120                } else {
 3121                    false
 3122                };
 3123
 3124                if continue_showing {
 3125                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3126                } else {
 3127                    self.hide_context_menu(window, cx);
 3128                }
 3129            }
 3130
 3131            hide_hover(self, cx);
 3132
 3133            if old_cursor_position.to_display_point(&display_map).row()
 3134                != new_cursor_position.to_display_point(&display_map).row()
 3135            {
 3136                self.available_code_actions.take();
 3137            }
 3138            self.refresh_code_actions(window, cx);
 3139            self.refresh_document_highlights(cx);
 3140            refresh_linked_ranges(self, window, cx);
 3141
 3142            self.refresh_selected_text_highlights(false, window, cx);
 3143            self.refresh_matching_bracket_highlights(window, cx);
 3144            self.update_visible_edit_prediction(window, cx);
 3145            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3146            self.inline_blame_popover.take();
 3147            if self.git_blame_inline_enabled {
 3148                self.start_inline_blame_timer(window, cx);
 3149            }
 3150        }
 3151
 3152        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3153        cx.emit(EditorEvent::SelectionsChanged { local });
 3154
 3155        let selections = &self.selections.disjoint_anchors_arc();
 3156        if selections.len() == 1 {
 3157            cx.emit(SearchEvent::ActiveMatchChanged)
 3158        }
 3159        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3160            let inmemory_selections = selections
 3161                .iter()
 3162                .map(|s| {
 3163                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3164                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3165                })
 3166                .collect();
 3167            self.update_restoration_data(cx, |data| {
 3168                data.selections = inmemory_selections;
 3169            });
 3170
 3171            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3172                && let Some(workspace_id) =
 3173                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3174            {
 3175                let snapshot = self.buffer().read(cx).snapshot(cx);
 3176                let selections = selections.clone();
 3177                let background_executor = cx.background_executor().clone();
 3178                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3179                self.serialize_selections = cx.background_spawn(async move {
 3180                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3181                    let db_selections = selections
 3182                        .iter()
 3183                        .map(|selection| {
 3184                            (
 3185                                selection.start.to_offset(&snapshot),
 3186                                selection.end.to_offset(&snapshot),
 3187                            )
 3188                        })
 3189                        .collect();
 3190
 3191                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3192                        .await
 3193                        .with_context(|| {
 3194                            format!(
 3195                                "persisting editor selections for editor {editor_id}, \
 3196                                workspace {workspace_id:?}"
 3197                            )
 3198                        })
 3199                        .log_err();
 3200                });
 3201            }
 3202        }
 3203
 3204        cx.notify();
 3205    }
 3206
 3207    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3208        use text::ToOffset as _;
 3209        use text::ToPoint as _;
 3210
 3211        if self.mode.is_minimap()
 3212            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3213        {
 3214            return;
 3215        }
 3216
 3217        if !self.buffer().read(cx).is_singleton() {
 3218            return;
 3219        }
 3220
 3221        let display_snapshot = self
 3222            .display_map
 3223            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3224        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3225            return;
 3226        };
 3227        let inmemory_folds = display_snapshot
 3228            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3229            .map(|fold| {
 3230                fold.range.start.text_anchor.to_point(&snapshot)
 3231                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3232            })
 3233            .collect();
 3234        self.update_restoration_data(cx, |data| {
 3235            data.folds = inmemory_folds;
 3236        });
 3237
 3238        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3239            return;
 3240        };
 3241        let background_executor = cx.background_executor().clone();
 3242        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3243        let db_folds = display_snapshot
 3244            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3245            .map(|fold| {
 3246                (
 3247                    fold.range.start.text_anchor.to_offset(&snapshot),
 3248                    fold.range.end.text_anchor.to_offset(&snapshot),
 3249                )
 3250            })
 3251            .collect();
 3252        self.serialize_folds = cx.background_spawn(async move {
 3253            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3254            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3255                .await
 3256                .with_context(|| {
 3257                    format!(
 3258                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3259                    )
 3260                })
 3261                .log_err();
 3262        });
 3263    }
 3264
 3265    pub fn sync_selections(
 3266        &mut self,
 3267        other: Entity<Editor>,
 3268        cx: &mut Context<Self>,
 3269    ) -> gpui::Subscription {
 3270        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3271        if !other_selections.is_empty() {
 3272            self.selections.change_with(cx, |selections| {
 3273                selections.select_anchors(other_selections);
 3274            });
 3275        }
 3276
 3277        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3278            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3279                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3280                if other_selections.is_empty() {
 3281                    return;
 3282                }
 3283                this.selections.change_with(cx, |selections| {
 3284                    selections.select_anchors(other_selections);
 3285                });
 3286            }
 3287        });
 3288
 3289        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3290            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3291                let these_selections = this.selections.disjoint_anchors().to_vec();
 3292                if these_selections.is_empty() {
 3293                    return;
 3294                }
 3295                other.update(cx, |other_editor, cx| {
 3296                    other_editor.selections.change_with(cx, |selections| {
 3297                        selections.select_anchors(these_selections);
 3298                    })
 3299                });
 3300            }
 3301        });
 3302
 3303        Subscription::join(other_subscription, this_subscription)
 3304    }
 3305
 3306    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3307    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3308    /// effects of selection change occur at the end of the transaction.
 3309    pub fn change_selections<R>(
 3310        &mut self,
 3311        effects: SelectionEffects,
 3312        window: &mut Window,
 3313        cx: &mut Context<Self>,
 3314        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3315    ) -> R {
 3316        if let Some(state) = &mut self.deferred_selection_effects_state {
 3317            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3318            state.effects.completions = effects.completions;
 3319            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3320            let (changed, result) = self.selections.change_with(cx, change);
 3321            state.changed |= changed;
 3322            return result;
 3323        }
 3324        let mut state = DeferredSelectionEffectsState {
 3325            changed: false,
 3326            effects,
 3327            old_cursor_position: self.selections.newest_anchor().head(),
 3328            history_entry: SelectionHistoryEntry {
 3329                selections: self.selections.disjoint_anchors_arc(),
 3330                select_next_state: self.select_next_state.clone(),
 3331                select_prev_state: self.select_prev_state.clone(),
 3332                add_selections_state: self.add_selections_state.clone(),
 3333            },
 3334        };
 3335        let (changed, result) = self.selections.change_with(cx, change);
 3336        state.changed = state.changed || changed;
 3337        if self.defer_selection_effects {
 3338            self.deferred_selection_effects_state = Some(state);
 3339        } else {
 3340            self.apply_selection_effects(state, window, cx);
 3341        }
 3342        result
 3343    }
 3344
 3345    /// Defers the effects of selection change, so that the effects of multiple calls to
 3346    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3347    /// to selection history and the state of popovers based on selection position aren't
 3348    /// erroneously updated.
 3349    pub fn with_selection_effects_deferred<R>(
 3350        &mut self,
 3351        window: &mut Window,
 3352        cx: &mut Context<Self>,
 3353        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3354    ) -> R {
 3355        let already_deferred = self.defer_selection_effects;
 3356        self.defer_selection_effects = true;
 3357        let result = update(self, window, cx);
 3358        if !already_deferred {
 3359            self.defer_selection_effects = false;
 3360            if let Some(state) = self.deferred_selection_effects_state.take() {
 3361                self.apply_selection_effects(state, window, cx);
 3362            }
 3363        }
 3364        result
 3365    }
 3366
 3367    fn apply_selection_effects(
 3368        &mut self,
 3369        state: DeferredSelectionEffectsState,
 3370        window: &mut Window,
 3371        cx: &mut Context<Self>,
 3372    ) {
 3373        if state.changed {
 3374            self.selection_history.push(state.history_entry);
 3375
 3376            if let Some(autoscroll) = state.effects.scroll {
 3377                self.request_autoscroll(autoscroll, cx);
 3378            }
 3379
 3380            let old_cursor_position = &state.old_cursor_position;
 3381
 3382            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3383
 3384            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3385                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3386            }
 3387        }
 3388    }
 3389
 3390    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3391    where
 3392        I: IntoIterator<Item = (Range<S>, T)>,
 3393        S: ToOffset,
 3394        T: Into<Arc<str>>,
 3395    {
 3396        if self.read_only(cx) {
 3397            return;
 3398        }
 3399
 3400        self.buffer
 3401            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3402    }
 3403
 3404    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3405    where
 3406        I: IntoIterator<Item = (Range<S>, T)>,
 3407        S: ToOffset,
 3408        T: Into<Arc<str>>,
 3409    {
 3410        if self.read_only(cx) {
 3411            return;
 3412        }
 3413
 3414        self.buffer.update(cx, |buffer, cx| {
 3415            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3416        });
 3417    }
 3418
 3419    pub fn edit_with_block_indent<I, S, T>(
 3420        &mut self,
 3421        edits: I,
 3422        original_indent_columns: Vec<Option<u32>>,
 3423        cx: &mut Context<Self>,
 3424    ) where
 3425        I: IntoIterator<Item = (Range<S>, T)>,
 3426        S: ToOffset,
 3427        T: Into<Arc<str>>,
 3428    {
 3429        if self.read_only(cx) {
 3430            return;
 3431        }
 3432
 3433        self.buffer.update(cx, |buffer, cx| {
 3434            buffer.edit(
 3435                edits,
 3436                Some(AutoindentMode::Block {
 3437                    original_indent_columns,
 3438                }),
 3439                cx,
 3440            )
 3441        });
 3442    }
 3443
 3444    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3445        self.hide_context_menu(window, cx);
 3446
 3447        match phase {
 3448            SelectPhase::Begin {
 3449                position,
 3450                add,
 3451                click_count,
 3452            } => self.begin_selection(position, add, click_count, window, cx),
 3453            SelectPhase::BeginColumnar {
 3454                position,
 3455                goal_column,
 3456                reset,
 3457                mode,
 3458            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3459            SelectPhase::Extend {
 3460                position,
 3461                click_count,
 3462            } => self.extend_selection(position, click_count, window, cx),
 3463            SelectPhase::Update {
 3464                position,
 3465                goal_column,
 3466                scroll_delta,
 3467            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3468            SelectPhase::End => self.end_selection(window, cx),
 3469        }
 3470    }
 3471
 3472    fn extend_selection(
 3473        &mut self,
 3474        position: DisplayPoint,
 3475        click_count: usize,
 3476        window: &mut Window,
 3477        cx: &mut Context<Self>,
 3478    ) {
 3479        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3480        let tail = self.selections.newest::<usize>(&display_map).tail();
 3481        let click_count = click_count.max(match self.selections.select_mode() {
 3482            SelectMode::Character => 1,
 3483            SelectMode::Word(_) => 2,
 3484            SelectMode::Line(_) => 3,
 3485            SelectMode::All => 4,
 3486        });
 3487        self.begin_selection(position, false, click_count, window, cx);
 3488
 3489        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3490
 3491        let current_selection = match self.selections.select_mode() {
 3492            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3493            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3494        };
 3495
 3496        let mut pending_selection = self
 3497            .selections
 3498            .pending_anchor()
 3499            .cloned()
 3500            .expect("extend_selection not called with pending selection");
 3501
 3502        if pending_selection
 3503            .start
 3504            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3505            == Ordering::Greater
 3506        {
 3507            pending_selection.start = current_selection.start;
 3508        }
 3509        if pending_selection
 3510            .end
 3511            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3512            == Ordering::Less
 3513        {
 3514            pending_selection.end = current_selection.end;
 3515            pending_selection.reversed = true;
 3516        }
 3517
 3518        let mut pending_mode = self.selections.pending_mode().unwrap();
 3519        match &mut pending_mode {
 3520            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3521            _ => {}
 3522        }
 3523
 3524        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3525            SelectionEffects::scroll(Autoscroll::fit())
 3526        } else {
 3527            SelectionEffects::no_scroll()
 3528        };
 3529
 3530        self.change_selections(effects, window, cx, |s| {
 3531            s.set_pending(pending_selection.clone(), pending_mode);
 3532            s.set_is_extending(true);
 3533        });
 3534    }
 3535
 3536    fn begin_selection(
 3537        &mut self,
 3538        position: DisplayPoint,
 3539        add: bool,
 3540        click_count: usize,
 3541        window: &mut Window,
 3542        cx: &mut Context<Self>,
 3543    ) {
 3544        if !self.focus_handle.is_focused(window) {
 3545            self.last_focused_descendant = None;
 3546            window.focus(&self.focus_handle);
 3547        }
 3548
 3549        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3550        let buffer = display_map.buffer_snapshot();
 3551        let position = display_map.clip_point(position, Bias::Left);
 3552
 3553        let start;
 3554        let end;
 3555        let mode;
 3556        let mut auto_scroll;
 3557        match click_count {
 3558            1 => {
 3559                start = buffer.anchor_before(position.to_point(&display_map));
 3560                end = start;
 3561                mode = SelectMode::Character;
 3562                auto_scroll = true;
 3563            }
 3564            2 => {
 3565                let position = display_map
 3566                    .clip_point(position, Bias::Left)
 3567                    .to_offset(&display_map, Bias::Left);
 3568                let (range, _) = buffer.surrounding_word(position, None);
 3569                start = buffer.anchor_before(range.start);
 3570                end = buffer.anchor_before(range.end);
 3571                mode = SelectMode::Word(start..end);
 3572                auto_scroll = true;
 3573            }
 3574            3 => {
 3575                let position = display_map
 3576                    .clip_point(position, Bias::Left)
 3577                    .to_point(&display_map);
 3578                let line_start = display_map.prev_line_boundary(position).0;
 3579                let next_line_start = buffer.clip_point(
 3580                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3581                    Bias::Left,
 3582                );
 3583                start = buffer.anchor_before(line_start);
 3584                end = buffer.anchor_before(next_line_start);
 3585                mode = SelectMode::Line(start..end);
 3586                auto_scroll = true;
 3587            }
 3588            _ => {
 3589                start = buffer.anchor_before(0);
 3590                end = buffer.anchor_before(buffer.len());
 3591                mode = SelectMode::All;
 3592                auto_scroll = false;
 3593            }
 3594        }
 3595        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3596
 3597        let point_to_delete: Option<usize> = {
 3598            let selected_points: Vec<Selection<Point>> =
 3599                self.selections.disjoint_in_range(start..end, &display_map);
 3600
 3601            if !add || click_count > 1 {
 3602                None
 3603            } else if !selected_points.is_empty() {
 3604                Some(selected_points[0].id)
 3605            } else {
 3606                let clicked_point_already_selected =
 3607                    self.selections.disjoint_anchors().iter().find(|selection| {
 3608                        selection.start.to_point(buffer) == start.to_point(buffer)
 3609                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3610                    });
 3611
 3612                clicked_point_already_selected.map(|selection| selection.id)
 3613            }
 3614        };
 3615
 3616        let selections_count = self.selections.count();
 3617        let effects = if auto_scroll {
 3618            SelectionEffects::default()
 3619        } else {
 3620            SelectionEffects::no_scroll()
 3621        };
 3622
 3623        self.change_selections(effects, window, cx, |s| {
 3624            if let Some(point_to_delete) = point_to_delete {
 3625                s.delete(point_to_delete);
 3626
 3627                if selections_count == 1 {
 3628                    s.set_pending_anchor_range(start..end, mode);
 3629                }
 3630            } else {
 3631                if !add {
 3632                    s.clear_disjoint();
 3633                }
 3634
 3635                s.set_pending_anchor_range(start..end, mode);
 3636            }
 3637        });
 3638    }
 3639
 3640    fn begin_columnar_selection(
 3641        &mut self,
 3642        position: DisplayPoint,
 3643        goal_column: u32,
 3644        reset: bool,
 3645        mode: ColumnarMode,
 3646        window: &mut Window,
 3647        cx: &mut Context<Self>,
 3648    ) {
 3649        if !self.focus_handle.is_focused(window) {
 3650            self.last_focused_descendant = None;
 3651            window.focus(&self.focus_handle);
 3652        }
 3653
 3654        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3655
 3656        if reset {
 3657            let pointer_position = display_map
 3658                .buffer_snapshot()
 3659                .anchor_before(position.to_point(&display_map));
 3660
 3661            self.change_selections(
 3662                SelectionEffects::scroll(Autoscroll::newest()),
 3663                window,
 3664                cx,
 3665                |s| {
 3666                    s.clear_disjoint();
 3667                    s.set_pending_anchor_range(
 3668                        pointer_position..pointer_position,
 3669                        SelectMode::Character,
 3670                    );
 3671                },
 3672            );
 3673        };
 3674
 3675        let tail = self.selections.newest::<Point>(&display_map).tail();
 3676        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3677        self.columnar_selection_state = match mode {
 3678            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3679                selection_tail: selection_anchor,
 3680                display_point: if reset {
 3681                    if position.column() != goal_column {
 3682                        Some(DisplayPoint::new(position.row(), goal_column))
 3683                    } else {
 3684                        None
 3685                    }
 3686                } else {
 3687                    None
 3688                },
 3689            }),
 3690            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3691                selection_tail: selection_anchor,
 3692            }),
 3693        };
 3694
 3695        if !reset {
 3696            self.select_columns(position, goal_column, &display_map, window, cx);
 3697        }
 3698    }
 3699
 3700    fn update_selection(
 3701        &mut self,
 3702        position: DisplayPoint,
 3703        goal_column: u32,
 3704        scroll_delta: gpui::Point<f32>,
 3705        window: &mut Window,
 3706        cx: &mut Context<Self>,
 3707    ) {
 3708        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3709
 3710        if self.columnar_selection_state.is_some() {
 3711            self.select_columns(position, goal_column, &display_map, window, cx);
 3712        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3713            let buffer = display_map.buffer_snapshot();
 3714            let head;
 3715            let tail;
 3716            let mode = self.selections.pending_mode().unwrap();
 3717            match &mode {
 3718                SelectMode::Character => {
 3719                    head = position.to_point(&display_map);
 3720                    tail = pending.tail().to_point(buffer);
 3721                }
 3722                SelectMode::Word(original_range) => {
 3723                    let offset = display_map
 3724                        .clip_point(position, Bias::Left)
 3725                        .to_offset(&display_map, Bias::Left);
 3726                    let original_range = original_range.to_offset(buffer);
 3727
 3728                    let head_offset = if buffer.is_inside_word(offset, None)
 3729                        || original_range.contains(&offset)
 3730                    {
 3731                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3732                        if word_range.start < original_range.start {
 3733                            word_range.start
 3734                        } else {
 3735                            word_range.end
 3736                        }
 3737                    } else {
 3738                        offset
 3739                    };
 3740
 3741                    head = head_offset.to_point(buffer);
 3742                    if head_offset <= original_range.start {
 3743                        tail = original_range.end.to_point(buffer);
 3744                    } else {
 3745                        tail = original_range.start.to_point(buffer);
 3746                    }
 3747                }
 3748                SelectMode::Line(original_range) => {
 3749                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3750
 3751                    let position = display_map
 3752                        .clip_point(position, Bias::Left)
 3753                        .to_point(&display_map);
 3754                    let line_start = display_map.prev_line_boundary(position).0;
 3755                    let next_line_start = buffer.clip_point(
 3756                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3757                        Bias::Left,
 3758                    );
 3759
 3760                    if line_start < original_range.start {
 3761                        head = line_start
 3762                    } else {
 3763                        head = next_line_start
 3764                    }
 3765
 3766                    if head <= original_range.start {
 3767                        tail = original_range.end;
 3768                    } else {
 3769                        tail = original_range.start;
 3770                    }
 3771                }
 3772                SelectMode::All => {
 3773                    return;
 3774                }
 3775            };
 3776
 3777            if head < tail {
 3778                pending.start = buffer.anchor_before(head);
 3779                pending.end = buffer.anchor_before(tail);
 3780                pending.reversed = true;
 3781            } else {
 3782                pending.start = buffer.anchor_before(tail);
 3783                pending.end = buffer.anchor_before(head);
 3784                pending.reversed = false;
 3785            }
 3786
 3787            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3788                s.set_pending(pending.clone(), mode);
 3789            });
 3790        } else {
 3791            log::error!("update_selection dispatched with no pending selection");
 3792            return;
 3793        }
 3794
 3795        self.apply_scroll_delta(scroll_delta, window, cx);
 3796        cx.notify();
 3797    }
 3798
 3799    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3800        self.columnar_selection_state.take();
 3801        if let Some(pending_mode) = self.selections.pending_mode() {
 3802            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3803            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3804                s.select(selections);
 3805                s.clear_pending();
 3806                if s.is_extending() {
 3807                    s.set_is_extending(false);
 3808                } else {
 3809                    s.set_select_mode(pending_mode);
 3810                }
 3811            });
 3812        }
 3813    }
 3814
 3815    fn select_columns(
 3816        &mut self,
 3817        head: DisplayPoint,
 3818        goal_column: u32,
 3819        display_map: &DisplaySnapshot,
 3820        window: &mut Window,
 3821        cx: &mut Context<Self>,
 3822    ) {
 3823        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3824            return;
 3825        };
 3826
 3827        let tail = match columnar_state {
 3828            ColumnarSelectionState::FromMouse {
 3829                selection_tail,
 3830                display_point,
 3831            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3832            ColumnarSelectionState::FromSelection { selection_tail } => {
 3833                selection_tail.to_display_point(display_map)
 3834            }
 3835        };
 3836
 3837        let start_row = cmp::min(tail.row(), head.row());
 3838        let end_row = cmp::max(tail.row(), head.row());
 3839        let start_column = cmp::min(tail.column(), goal_column);
 3840        let end_column = cmp::max(tail.column(), goal_column);
 3841        let reversed = start_column < tail.column();
 3842
 3843        let selection_ranges = (start_row.0..=end_row.0)
 3844            .map(DisplayRow)
 3845            .filter_map(|row| {
 3846                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3847                    || start_column <= display_map.line_len(row))
 3848                    && !display_map.is_block_line(row)
 3849                {
 3850                    let start = display_map
 3851                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3852                        .to_point(display_map);
 3853                    let end = display_map
 3854                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3855                        .to_point(display_map);
 3856                    if reversed {
 3857                        Some(end..start)
 3858                    } else {
 3859                        Some(start..end)
 3860                    }
 3861                } else {
 3862                    None
 3863                }
 3864            })
 3865            .collect::<Vec<_>>();
 3866        if selection_ranges.is_empty() {
 3867            return;
 3868        }
 3869
 3870        let ranges = match columnar_state {
 3871            ColumnarSelectionState::FromMouse { .. } => {
 3872                let mut non_empty_ranges = selection_ranges
 3873                    .iter()
 3874                    .filter(|selection_range| selection_range.start != selection_range.end)
 3875                    .peekable();
 3876                if non_empty_ranges.peek().is_some() {
 3877                    non_empty_ranges.cloned().collect()
 3878                } else {
 3879                    selection_ranges
 3880                }
 3881            }
 3882            _ => selection_ranges,
 3883        };
 3884
 3885        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3886            s.select_ranges(ranges);
 3887        });
 3888        cx.notify();
 3889    }
 3890
 3891    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3892        self.selections
 3893            .all_adjusted(snapshot)
 3894            .iter()
 3895            .any(|selection| !selection.is_empty())
 3896    }
 3897
 3898    pub fn has_pending_nonempty_selection(&self) -> bool {
 3899        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3900            Some(Selection { start, end, .. }) => start != end,
 3901            None => false,
 3902        };
 3903
 3904        pending_nonempty_selection
 3905            || (self.columnar_selection_state.is_some()
 3906                && self.selections.disjoint_anchors().len() > 1)
 3907    }
 3908
 3909    pub fn has_pending_selection(&self) -> bool {
 3910        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3911    }
 3912
 3913    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3914        self.selection_mark_mode = false;
 3915        self.selection_drag_state = SelectionDragState::None;
 3916
 3917        if self.clear_expanded_diff_hunks(cx) {
 3918            cx.notify();
 3919            return;
 3920        }
 3921        if self.dismiss_menus_and_popups(true, window, cx) {
 3922            return;
 3923        }
 3924
 3925        if self.mode.is_full()
 3926            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3927        {
 3928            return;
 3929        }
 3930
 3931        cx.propagate();
 3932    }
 3933
 3934    pub fn dismiss_menus_and_popups(
 3935        &mut self,
 3936        is_user_requested: bool,
 3937        window: &mut Window,
 3938        cx: &mut Context<Self>,
 3939    ) -> bool {
 3940        if self.take_rename(false, window, cx).is_some() {
 3941            return true;
 3942        }
 3943
 3944        if self.hide_blame_popover(true, cx) {
 3945            return true;
 3946        }
 3947
 3948        if hide_hover(self, cx) {
 3949            return true;
 3950        }
 3951
 3952        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3953            return true;
 3954        }
 3955
 3956        if self.hide_context_menu(window, cx).is_some() {
 3957            return true;
 3958        }
 3959
 3960        if self.mouse_context_menu.take().is_some() {
 3961            return true;
 3962        }
 3963
 3964        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3965            return true;
 3966        }
 3967
 3968        if self.snippet_stack.pop().is_some() {
 3969            return true;
 3970        }
 3971
 3972        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3973            self.dismiss_diagnostics(cx);
 3974            return true;
 3975        }
 3976
 3977        false
 3978    }
 3979
 3980    fn linked_editing_ranges_for(
 3981        &self,
 3982        selection: Range<text::Anchor>,
 3983        cx: &App,
 3984    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3985        if self.linked_edit_ranges.is_empty() {
 3986            return None;
 3987        }
 3988        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3989            selection.end.buffer_id.and_then(|end_buffer_id| {
 3990                if selection.start.buffer_id != Some(end_buffer_id) {
 3991                    return None;
 3992                }
 3993                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3994                let snapshot = buffer.read(cx).snapshot();
 3995                self.linked_edit_ranges
 3996                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3997                    .map(|ranges| (ranges, snapshot, buffer))
 3998            })?;
 3999        use text::ToOffset as TO;
 4000        // find offset from the start of current range to current cursor position
 4001        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4002
 4003        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4004        let start_difference = start_offset - start_byte_offset;
 4005        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4006        let end_difference = end_offset - start_byte_offset;
 4007        // Current range has associated linked ranges.
 4008        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4009        for range in linked_ranges.iter() {
 4010            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4011            let end_offset = start_offset + end_difference;
 4012            let start_offset = start_offset + start_difference;
 4013            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4014                continue;
 4015            }
 4016            if self.selections.disjoint_anchor_ranges().any(|s| {
 4017                if s.start.buffer_id != selection.start.buffer_id
 4018                    || s.end.buffer_id != selection.end.buffer_id
 4019                {
 4020                    return false;
 4021                }
 4022                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4023                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4024            }) {
 4025                continue;
 4026            }
 4027            let start = buffer_snapshot.anchor_after(start_offset);
 4028            let end = buffer_snapshot.anchor_after(end_offset);
 4029            linked_edits
 4030                .entry(buffer.clone())
 4031                .or_default()
 4032                .push(start..end);
 4033        }
 4034        Some(linked_edits)
 4035    }
 4036
 4037    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4038        let text: Arc<str> = text.into();
 4039
 4040        if self.read_only(cx) {
 4041            return;
 4042        }
 4043
 4044        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4045
 4046        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4047        let mut bracket_inserted = false;
 4048        let mut edits = Vec::new();
 4049        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4050        let mut new_selections = Vec::with_capacity(selections.len());
 4051        let mut new_autoclose_regions = Vec::new();
 4052        let snapshot = self.buffer.read(cx).read(cx);
 4053        let mut clear_linked_edit_ranges = false;
 4054
 4055        for (selection, autoclose_region) in
 4056            self.selections_with_autoclose_regions(selections, &snapshot)
 4057        {
 4058            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4059                // Determine if the inserted text matches the opening or closing
 4060                // bracket of any of this language's bracket pairs.
 4061                let mut bracket_pair = None;
 4062                let mut is_bracket_pair_start = false;
 4063                let mut is_bracket_pair_end = false;
 4064                if !text.is_empty() {
 4065                    let mut bracket_pair_matching_end = None;
 4066                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4067                    //  and they are removing the character that triggered IME popup.
 4068                    for (pair, enabled) in scope.brackets() {
 4069                        if !pair.close && !pair.surround {
 4070                            continue;
 4071                        }
 4072
 4073                        if enabled && pair.start.ends_with(text.as_ref()) {
 4074                            let prefix_len = pair.start.len() - text.len();
 4075                            let preceding_text_matches_prefix = prefix_len == 0
 4076                                || (selection.start.column >= (prefix_len as u32)
 4077                                    && snapshot.contains_str_at(
 4078                                        Point::new(
 4079                                            selection.start.row,
 4080                                            selection.start.column - (prefix_len as u32),
 4081                                        ),
 4082                                        &pair.start[..prefix_len],
 4083                                    ));
 4084                            if preceding_text_matches_prefix {
 4085                                bracket_pair = Some(pair.clone());
 4086                                is_bracket_pair_start = true;
 4087                                break;
 4088                            }
 4089                        }
 4090                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4091                        {
 4092                            // take first bracket pair matching end, but don't break in case a later bracket
 4093                            // pair matches start
 4094                            bracket_pair_matching_end = Some(pair.clone());
 4095                        }
 4096                    }
 4097                    if let Some(end) = bracket_pair_matching_end
 4098                        && bracket_pair.is_none()
 4099                    {
 4100                        bracket_pair = Some(end);
 4101                        is_bracket_pair_end = true;
 4102                    }
 4103                }
 4104
 4105                if let Some(bracket_pair) = bracket_pair {
 4106                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4107                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4108                    let auto_surround =
 4109                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4110                    if selection.is_empty() {
 4111                        if is_bracket_pair_start {
 4112                            // If the inserted text is a suffix of an opening bracket and the
 4113                            // selection is preceded by the rest of the opening bracket, then
 4114                            // insert the closing bracket.
 4115                            let following_text_allows_autoclose = snapshot
 4116                                .chars_at(selection.start)
 4117                                .next()
 4118                                .is_none_or(|c| scope.should_autoclose_before(c));
 4119
 4120                            let preceding_text_allows_autoclose = selection.start.column == 0
 4121                                || snapshot
 4122                                    .reversed_chars_at(selection.start)
 4123                                    .next()
 4124                                    .is_none_or(|c| {
 4125                                        bracket_pair.start != bracket_pair.end
 4126                                            || !snapshot
 4127                                                .char_classifier_at(selection.start)
 4128                                                .is_word(c)
 4129                                    });
 4130
 4131                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4132                                && bracket_pair.start.len() == 1
 4133                            {
 4134                                let target = bracket_pair.start.chars().next().unwrap();
 4135                                let current_line_count = snapshot
 4136                                    .reversed_chars_at(selection.start)
 4137                                    .take_while(|&c| c != '\n')
 4138                                    .filter(|&c| c == target)
 4139                                    .count();
 4140                                current_line_count % 2 == 1
 4141                            } else {
 4142                                false
 4143                            };
 4144
 4145                            if autoclose
 4146                                && bracket_pair.close
 4147                                && following_text_allows_autoclose
 4148                                && preceding_text_allows_autoclose
 4149                                && !is_closing_quote
 4150                            {
 4151                                let anchor = snapshot.anchor_before(selection.end);
 4152                                new_selections.push((selection.map(|_| anchor), text.len()));
 4153                                new_autoclose_regions.push((
 4154                                    anchor,
 4155                                    text.len(),
 4156                                    selection.id,
 4157                                    bracket_pair.clone(),
 4158                                ));
 4159                                edits.push((
 4160                                    selection.range(),
 4161                                    format!("{}{}", text, bracket_pair.end).into(),
 4162                                ));
 4163                                bracket_inserted = true;
 4164                                continue;
 4165                            }
 4166                        }
 4167
 4168                        if let Some(region) = autoclose_region {
 4169                            // If the selection is followed by an auto-inserted closing bracket,
 4170                            // then don't insert that closing bracket again; just move the selection
 4171                            // past the closing bracket.
 4172                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4173                                && text.as_ref() == region.pair.end.as_str()
 4174                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4175                            if should_skip {
 4176                                let anchor = snapshot.anchor_after(selection.end);
 4177                                new_selections
 4178                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4179                                continue;
 4180                            }
 4181                        }
 4182
 4183                        let always_treat_brackets_as_autoclosed = snapshot
 4184                            .language_settings_at(selection.start, cx)
 4185                            .always_treat_brackets_as_autoclosed;
 4186                        if always_treat_brackets_as_autoclosed
 4187                            && is_bracket_pair_end
 4188                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4189                        {
 4190                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4191                            // and the inserted text is a closing bracket and the selection is followed
 4192                            // by the closing bracket then move the selection past the closing bracket.
 4193                            let anchor = snapshot.anchor_after(selection.end);
 4194                            new_selections.push((selection.map(|_| anchor), text.len()));
 4195                            continue;
 4196                        }
 4197                    }
 4198                    // If an opening bracket is 1 character long and is typed while
 4199                    // text is selected, then surround that text with the bracket pair.
 4200                    else if auto_surround
 4201                        && bracket_pair.surround
 4202                        && is_bracket_pair_start
 4203                        && bracket_pair.start.chars().count() == 1
 4204                    {
 4205                        edits.push((selection.start..selection.start, text.clone()));
 4206                        edits.push((
 4207                            selection.end..selection.end,
 4208                            bracket_pair.end.as_str().into(),
 4209                        ));
 4210                        bracket_inserted = true;
 4211                        new_selections.push((
 4212                            Selection {
 4213                                id: selection.id,
 4214                                start: snapshot.anchor_after(selection.start),
 4215                                end: snapshot.anchor_before(selection.end),
 4216                                reversed: selection.reversed,
 4217                                goal: selection.goal,
 4218                            },
 4219                            0,
 4220                        ));
 4221                        continue;
 4222                    }
 4223                }
 4224            }
 4225
 4226            if self.auto_replace_emoji_shortcode
 4227                && selection.is_empty()
 4228                && text.as_ref().ends_with(':')
 4229                && let Some(possible_emoji_short_code) =
 4230                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4231                && !possible_emoji_short_code.is_empty()
 4232                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4233            {
 4234                let emoji_shortcode_start = Point::new(
 4235                    selection.start.row,
 4236                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4237                );
 4238
 4239                // Remove shortcode from buffer
 4240                edits.push((
 4241                    emoji_shortcode_start..selection.start,
 4242                    "".to_string().into(),
 4243                ));
 4244                new_selections.push((
 4245                    Selection {
 4246                        id: selection.id,
 4247                        start: snapshot.anchor_after(emoji_shortcode_start),
 4248                        end: snapshot.anchor_before(selection.start),
 4249                        reversed: selection.reversed,
 4250                        goal: selection.goal,
 4251                    },
 4252                    0,
 4253                ));
 4254
 4255                // Insert emoji
 4256                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4257                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4258                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4259
 4260                continue;
 4261            }
 4262
 4263            // If not handling any auto-close operation, then just replace the selected
 4264            // text with the given input and move the selection to the end of the
 4265            // newly inserted text.
 4266            let anchor = snapshot.anchor_after(selection.end);
 4267            if !self.linked_edit_ranges.is_empty() {
 4268                let start_anchor = snapshot.anchor_before(selection.start);
 4269
 4270                let is_word_char = text.chars().next().is_none_or(|char| {
 4271                    let classifier = snapshot
 4272                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4273                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4274                    classifier.is_word(char)
 4275                });
 4276
 4277                if is_word_char {
 4278                    if let Some(ranges) = self
 4279                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4280                    {
 4281                        for (buffer, edits) in ranges {
 4282                            linked_edits
 4283                                .entry(buffer.clone())
 4284                                .or_default()
 4285                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4286                        }
 4287                    }
 4288                } else {
 4289                    clear_linked_edit_ranges = true;
 4290                }
 4291            }
 4292
 4293            new_selections.push((selection.map(|_| anchor), 0));
 4294            edits.push((selection.start..selection.end, text.clone()));
 4295        }
 4296
 4297        drop(snapshot);
 4298
 4299        self.transact(window, cx, |this, window, cx| {
 4300            if clear_linked_edit_ranges {
 4301                this.linked_edit_ranges.clear();
 4302            }
 4303            let initial_buffer_versions =
 4304                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4305
 4306            this.buffer.update(cx, |buffer, cx| {
 4307                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4308            });
 4309            for (buffer, edits) in linked_edits {
 4310                buffer.update(cx, |buffer, cx| {
 4311                    let snapshot = buffer.snapshot();
 4312                    let edits = edits
 4313                        .into_iter()
 4314                        .map(|(range, text)| {
 4315                            use text::ToPoint as TP;
 4316                            let end_point = TP::to_point(&range.end, &snapshot);
 4317                            let start_point = TP::to_point(&range.start, &snapshot);
 4318                            (start_point..end_point, text)
 4319                        })
 4320                        .sorted_by_key(|(range, _)| range.start);
 4321                    buffer.edit(edits, None, cx);
 4322                })
 4323            }
 4324            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4325            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4326            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4327            let new_selections =
 4328                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4329                    .zip(new_selection_deltas)
 4330                    .map(|(selection, delta)| Selection {
 4331                        id: selection.id,
 4332                        start: selection.start + delta,
 4333                        end: selection.end + delta,
 4334                        reversed: selection.reversed,
 4335                        goal: SelectionGoal::None,
 4336                    })
 4337                    .collect::<Vec<_>>();
 4338
 4339            let mut i = 0;
 4340            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4341                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4342                let start = map.buffer_snapshot().anchor_before(position);
 4343                let end = map.buffer_snapshot().anchor_after(position);
 4344                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4345                    match existing_state
 4346                        .range
 4347                        .start
 4348                        .cmp(&start, map.buffer_snapshot())
 4349                    {
 4350                        Ordering::Less => i += 1,
 4351                        Ordering::Greater => break,
 4352                        Ordering::Equal => {
 4353                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4354                                Ordering::Less => i += 1,
 4355                                Ordering::Equal => break,
 4356                                Ordering::Greater => break,
 4357                            }
 4358                        }
 4359                    }
 4360                }
 4361                this.autoclose_regions.insert(
 4362                    i,
 4363                    AutocloseRegion {
 4364                        selection_id,
 4365                        range: start..end,
 4366                        pair,
 4367                    },
 4368                );
 4369            }
 4370
 4371            let had_active_edit_prediction = this.has_active_edit_prediction();
 4372            this.change_selections(
 4373                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4374                window,
 4375                cx,
 4376                |s| s.select(new_selections),
 4377            );
 4378
 4379            if !bracket_inserted
 4380                && let Some(on_type_format_task) =
 4381                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4382            {
 4383                on_type_format_task.detach_and_log_err(cx);
 4384            }
 4385
 4386            let editor_settings = EditorSettings::get_global(cx);
 4387            if bracket_inserted
 4388                && (editor_settings.auto_signature_help
 4389                    || editor_settings.show_signature_help_after_edits)
 4390            {
 4391                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4392            }
 4393
 4394            let trigger_in_words =
 4395                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4396            if this.hard_wrap.is_some() {
 4397                let latest: Range<Point> = this.selections.newest(&map).range();
 4398                if latest.is_empty()
 4399                    && this
 4400                        .buffer()
 4401                        .read(cx)
 4402                        .snapshot(cx)
 4403                        .line_len(MultiBufferRow(latest.start.row))
 4404                        == latest.start.column
 4405                {
 4406                    this.rewrap_impl(
 4407                        RewrapOptions {
 4408                            override_language_settings: true,
 4409                            preserve_existing_whitespace: true,
 4410                        },
 4411                        cx,
 4412                    )
 4413                }
 4414            }
 4415            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4416            refresh_linked_ranges(this, window, cx);
 4417            this.refresh_edit_prediction(true, false, window, cx);
 4418            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4419        });
 4420    }
 4421
 4422    fn find_possible_emoji_shortcode_at_position(
 4423        snapshot: &MultiBufferSnapshot,
 4424        position: Point,
 4425    ) -> Option<String> {
 4426        let mut chars = Vec::new();
 4427        let mut found_colon = false;
 4428        for char in snapshot.reversed_chars_at(position).take(100) {
 4429            // Found a possible emoji shortcode in the middle of the buffer
 4430            if found_colon {
 4431                if char.is_whitespace() {
 4432                    chars.reverse();
 4433                    return Some(chars.iter().collect());
 4434                }
 4435                // If the previous character is not a whitespace, we are in the middle of a word
 4436                // and we only want to complete the shortcode if the word is made up of other emojis
 4437                let mut containing_word = String::new();
 4438                for ch in snapshot
 4439                    .reversed_chars_at(position)
 4440                    .skip(chars.len() + 1)
 4441                    .take(100)
 4442                {
 4443                    if ch.is_whitespace() {
 4444                        break;
 4445                    }
 4446                    containing_word.push(ch);
 4447                }
 4448                let containing_word = containing_word.chars().rev().collect::<String>();
 4449                if util::word_consists_of_emojis(containing_word.as_str()) {
 4450                    chars.reverse();
 4451                    return Some(chars.iter().collect());
 4452                }
 4453            }
 4454
 4455            if char.is_whitespace() || !char.is_ascii() {
 4456                return None;
 4457            }
 4458            if char == ':' {
 4459                found_colon = true;
 4460            } else {
 4461                chars.push(char);
 4462            }
 4463        }
 4464        // Found a possible emoji shortcode at the beginning of the buffer
 4465        chars.reverse();
 4466        Some(chars.iter().collect())
 4467    }
 4468
 4469    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4470        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4471        self.transact(window, cx, |this, window, cx| {
 4472            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4473                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4474                let multi_buffer = this.buffer.read(cx);
 4475                let buffer = multi_buffer.snapshot(cx);
 4476                selections
 4477                    .iter()
 4478                    .map(|selection| {
 4479                        let start_point = selection.start.to_point(&buffer);
 4480                        let mut existing_indent =
 4481                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4482                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4483                        let start = selection.start;
 4484                        let end = selection.end;
 4485                        let selection_is_empty = start == end;
 4486                        let language_scope = buffer.language_scope_at(start);
 4487                        let (
 4488                            comment_delimiter,
 4489                            doc_delimiter,
 4490                            insert_extra_newline,
 4491                            indent_on_newline,
 4492                            indent_on_extra_newline,
 4493                        ) = if let Some(language) = &language_scope {
 4494                            let mut insert_extra_newline =
 4495                                insert_extra_newline_brackets(&buffer, start..end, language)
 4496                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4497
 4498                            // Comment extension on newline is allowed only for cursor selections
 4499                            let comment_delimiter = maybe!({
 4500                                if !selection_is_empty {
 4501                                    return None;
 4502                                }
 4503
 4504                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4505                                    return None;
 4506                                }
 4507
 4508                                let delimiters = language.line_comment_prefixes();
 4509                                let max_len_of_delimiter =
 4510                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4511                                let (snapshot, range) =
 4512                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4513
 4514                                let num_of_whitespaces = snapshot
 4515                                    .chars_for_range(range.clone())
 4516                                    .take_while(|c| c.is_whitespace())
 4517                                    .count();
 4518                                let comment_candidate = snapshot
 4519                                    .chars_for_range(range.clone())
 4520                                    .skip(num_of_whitespaces)
 4521                                    .take(max_len_of_delimiter)
 4522                                    .collect::<String>();
 4523                                let (delimiter, trimmed_len) = delimiters
 4524                                    .iter()
 4525                                    .filter_map(|delimiter| {
 4526                                        let prefix = delimiter.trim_end();
 4527                                        if comment_candidate.starts_with(prefix) {
 4528                                            Some((delimiter, prefix.len()))
 4529                                        } else {
 4530                                            None
 4531                                        }
 4532                                    })
 4533                                    .max_by_key(|(_, len)| *len)?;
 4534
 4535                                if let Some(BlockCommentConfig {
 4536                                    start: block_start, ..
 4537                                }) = language.block_comment()
 4538                                {
 4539                                    let block_start_trimmed = block_start.trim_end();
 4540                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4541                                        let line_content = snapshot
 4542                                            .chars_for_range(range)
 4543                                            .skip(num_of_whitespaces)
 4544                                            .take(block_start_trimmed.len())
 4545                                            .collect::<String>();
 4546
 4547                                        if line_content.starts_with(block_start_trimmed) {
 4548                                            return None;
 4549                                        }
 4550                                    }
 4551                                }
 4552
 4553                                let cursor_is_placed_after_comment_marker =
 4554                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4555                                if cursor_is_placed_after_comment_marker {
 4556                                    Some(delimiter.clone())
 4557                                } else {
 4558                                    None
 4559                                }
 4560                            });
 4561
 4562                            let mut indent_on_newline = IndentSize::spaces(0);
 4563                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4564
 4565                            let doc_delimiter = maybe!({
 4566                                if !selection_is_empty {
 4567                                    return None;
 4568                                }
 4569
 4570                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4571                                    return None;
 4572                                }
 4573
 4574                                let BlockCommentConfig {
 4575                                    start: start_tag,
 4576                                    end: end_tag,
 4577                                    prefix: delimiter,
 4578                                    tab_size: len,
 4579                                } = language.documentation_comment()?;
 4580                                let is_within_block_comment = buffer
 4581                                    .language_scope_at(start_point)
 4582                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4583                                if !is_within_block_comment {
 4584                                    return None;
 4585                                }
 4586
 4587                                let (snapshot, range) =
 4588                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4589
 4590                                let num_of_whitespaces = snapshot
 4591                                    .chars_for_range(range.clone())
 4592                                    .take_while(|c| c.is_whitespace())
 4593                                    .count();
 4594
 4595                                // 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.
 4596                                let column = start_point.column;
 4597                                let cursor_is_after_start_tag = {
 4598                                    let start_tag_len = start_tag.len();
 4599                                    let start_tag_line = snapshot
 4600                                        .chars_for_range(range.clone())
 4601                                        .skip(num_of_whitespaces)
 4602                                        .take(start_tag_len)
 4603                                        .collect::<String>();
 4604                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4605                                        num_of_whitespaces + start_tag_len <= column as usize
 4606                                    } else {
 4607                                        false
 4608                                    }
 4609                                };
 4610
 4611                                let cursor_is_after_delimiter = {
 4612                                    let delimiter_trim = delimiter.trim_end();
 4613                                    let delimiter_line = snapshot
 4614                                        .chars_for_range(range.clone())
 4615                                        .skip(num_of_whitespaces)
 4616                                        .take(delimiter_trim.len())
 4617                                        .collect::<String>();
 4618                                    if delimiter_line.starts_with(delimiter_trim) {
 4619                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4620                                    } else {
 4621                                        false
 4622                                    }
 4623                                };
 4624
 4625                                let cursor_is_before_end_tag_if_exists = {
 4626                                    let mut char_position = 0u32;
 4627                                    let mut end_tag_offset = None;
 4628
 4629                                    'outer: for chunk in snapshot.text_for_range(range) {
 4630                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4631                                            let chars_before_match =
 4632                                                chunk[..byte_pos].chars().count() as u32;
 4633                                            end_tag_offset =
 4634                                                Some(char_position + chars_before_match);
 4635                                            break 'outer;
 4636                                        }
 4637                                        char_position += chunk.chars().count() as u32;
 4638                                    }
 4639
 4640                                    if let Some(end_tag_offset) = end_tag_offset {
 4641                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4642                                        if cursor_is_after_start_tag {
 4643                                            if cursor_is_before_end_tag {
 4644                                                insert_extra_newline = true;
 4645                                            }
 4646                                            let cursor_is_at_start_of_end_tag =
 4647                                                column == end_tag_offset;
 4648                                            if cursor_is_at_start_of_end_tag {
 4649                                                indent_on_extra_newline.len = *len;
 4650                                            }
 4651                                        }
 4652                                        cursor_is_before_end_tag
 4653                                    } else {
 4654                                        true
 4655                                    }
 4656                                };
 4657
 4658                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4659                                    && cursor_is_before_end_tag_if_exists
 4660                                {
 4661                                    if cursor_is_after_start_tag {
 4662                                        indent_on_newline.len = *len;
 4663                                    }
 4664                                    Some(delimiter.clone())
 4665                                } else {
 4666                                    None
 4667                                }
 4668                            });
 4669
 4670                            (
 4671                                comment_delimiter,
 4672                                doc_delimiter,
 4673                                insert_extra_newline,
 4674                                indent_on_newline,
 4675                                indent_on_extra_newline,
 4676                            )
 4677                        } else {
 4678                            (
 4679                                None,
 4680                                None,
 4681                                false,
 4682                                IndentSize::default(),
 4683                                IndentSize::default(),
 4684                            )
 4685                        };
 4686
 4687                        let prevent_auto_indent = doc_delimiter.is_some();
 4688                        let delimiter = comment_delimiter.or(doc_delimiter);
 4689
 4690                        let capacity_for_delimiter =
 4691                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4692                        let mut new_text = String::with_capacity(
 4693                            1 + capacity_for_delimiter
 4694                                + existing_indent.len as usize
 4695                                + indent_on_newline.len as usize
 4696                                + indent_on_extra_newline.len as usize,
 4697                        );
 4698                        new_text.push('\n');
 4699                        new_text.extend(existing_indent.chars());
 4700                        new_text.extend(indent_on_newline.chars());
 4701
 4702                        if let Some(delimiter) = &delimiter {
 4703                            new_text.push_str(delimiter);
 4704                        }
 4705
 4706                        if insert_extra_newline {
 4707                            new_text.push('\n');
 4708                            new_text.extend(existing_indent.chars());
 4709                            new_text.extend(indent_on_extra_newline.chars());
 4710                        }
 4711
 4712                        let anchor = buffer.anchor_after(end);
 4713                        let new_selection = selection.map(|_| anchor);
 4714                        (
 4715                            ((start..end, new_text), prevent_auto_indent),
 4716                            (insert_extra_newline, new_selection),
 4717                        )
 4718                    })
 4719                    .unzip()
 4720            };
 4721
 4722            let mut auto_indent_edits = Vec::new();
 4723            let mut edits = Vec::new();
 4724            for (edit, prevent_auto_indent) in edits_with_flags {
 4725                if prevent_auto_indent {
 4726                    edits.push(edit);
 4727                } else {
 4728                    auto_indent_edits.push(edit);
 4729                }
 4730            }
 4731            if !edits.is_empty() {
 4732                this.edit(edits, cx);
 4733            }
 4734            if !auto_indent_edits.is_empty() {
 4735                this.edit_with_autoindent(auto_indent_edits, cx);
 4736            }
 4737
 4738            let buffer = this.buffer.read(cx).snapshot(cx);
 4739            let new_selections = selection_info
 4740                .into_iter()
 4741                .map(|(extra_newline_inserted, new_selection)| {
 4742                    let mut cursor = new_selection.end.to_point(&buffer);
 4743                    if extra_newline_inserted {
 4744                        cursor.row -= 1;
 4745                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4746                    }
 4747                    new_selection.map(|_| cursor)
 4748                })
 4749                .collect();
 4750
 4751            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4752            this.refresh_edit_prediction(true, false, window, cx);
 4753        });
 4754    }
 4755
 4756    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4757        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4758
 4759        let buffer = self.buffer.read(cx);
 4760        let snapshot = buffer.snapshot(cx);
 4761
 4762        let mut edits = Vec::new();
 4763        let mut rows = Vec::new();
 4764
 4765        for (rows_inserted, selection) in self
 4766            .selections
 4767            .all_adjusted(&self.display_snapshot(cx))
 4768            .into_iter()
 4769            .enumerate()
 4770        {
 4771            let cursor = selection.head();
 4772            let row = cursor.row;
 4773
 4774            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4775
 4776            let newline = "\n".to_string();
 4777            edits.push((start_of_line..start_of_line, newline));
 4778
 4779            rows.push(row + rows_inserted as u32);
 4780        }
 4781
 4782        self.transact(window, cx, |editor, window, cx| {
 4783            editor.edit(edits, cx);
 4784
 4785            editor.change_selections(Default::default(), window, cx, |s| {
 4786                let mut index = 0;
 4787                s.move_cursors_with(|map, _, _| {
 4788                    let row = rows[index];
 4789                    index += 1;
 4790
 4791                    let point = Point::new(row, 0);
 4792                    let boundary = map.next_line_boundary(point).1;
 4793                    let clipped = map.clip_point(boundary, Bias::Left);
 4794
 4795                    (clipped, SelectionGoal::None)
 4796                });
 4797            });
 4798
 4799            let mut indent_edits = Vec::new();
 4800            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4801            for row in rows {
 4802                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4803                for (row, indent) in indents {
 4804                    if indent.len == 0 {
 4805                        continue;
 4806                    }
 4807
 4808                    let text = match indent.kind {
 4809                        IndentKind::Space => " ".repeat(indent.len as usize),
 4810                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4811                    };
 4812                    let point = Point::new(row.0, 0);
 4813                    indent_edits.push((point..point, text));
 4814                }
 4815            }
 4816            editor.edit(indent_edits, cx);
 4817        });
 4818    }
 4819
 4820    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4821        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4822
 4823        let buffer = self.buffer.read(cx);
 4824        let snapshot = buffer.snapshot(cx);
 4825
 4826        let mut edits = Vec::new();
 4827        let mut rows = Vec::new();
 4828        let mut rows_inserted = 0;
 4829
 4830        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4831            let cursor = selection.head();
 4832            let row = cursor.row;
 4833
 4834            let point = Point::new(row + 1, 0);
 4835            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4836
 4837            let newline = "\n".to_string();
 4838            edits.push((start_of_line..start_of_line, newline));
 4839
 4840            rows_inserted += 1;
 4841            rows.push(row + rows_inserted);
 4842        }
 4843
 4844        self.transact(window, cx, |editor, window, cx| {
 4845            editor.edit(edits, cx);
 4846
 4847            editor.change_selections(Default::default(), window, cx, |s| {
 4848                let mut index = 0;
 4849                s.move_cursors_with(|map, _, _| {
 4850                    let row = rows[index];
 4851                    index += 1;
 4852
 4853                    let point = Point::new(row, 0);
 4854                    let boundary = map.next_line_boundary(point).1;
 4855                    let clipped = map.clip_point(boundary, Bias::Left);
 4856
 4857                    (clipped, SelectionGoal::None)
 4858                });
 4859            });
 4860
 4861            let mut indent_edits = Vec::new();
 4862            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4863            for row in rows {
 4864                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4865                for (row, indent) in indents {
 4866                    if indent.len == 0 {
 4867                        continue;
 4868                    }
 4869
 4870                    let text = match indent.kind {
 4871                        IndentKind::Space => " ".repeat(indent.len as usize),
 4872                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4873                    };
 4874                    let point = Point::new(row.0, 0);
 4875                    indent_edits.push((point..point, text));
 4876                }
 4877            }
 4878            editor.edit(indent_edits, cx);
 4879        });
 4880    }
 4881
 4882    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4883        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4884            original_indent_columns: Vec::new(),
 4885        });
 4886        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4887    }
 4888
 4889    fn insert_with_autoindent_mode(
 4890        &mut self,
 4891        text: &str,
 4892        autoindent_mode: Option<AutoindentMode>,
 4893        window: &mut Window,
 4894        cx: &mut Context<Self>,
 4895    ) {
 4896        if self.read_only(cx) {
 4897            return;
 4898        }
 4899
 4900        let text: Arc<str> = text.into();
 4901        self.transact(window, cx, |this, window, cx| {
 4902            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4903            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4904                let anchors = {
 4905                    let snapshot = buffer.read(cx);
 4906                    old_selections
 4907                        .iter()
 4908                        .map(|s| {
 4909                            let anchor = snapshot.anchor_after(s.head());
 4910                            s.map(|_| anchor)
 4911                        })
 4912                        .collect::<Vec<_>>()
 4913                };
 4914                buffer.edit(
 4915                    old_selections
 4916                        .iter()
 4917                        .map(|s| (s.start..s.end, text.clone())),
 4918                    autoindent_mode,
 4919                    cx,
 4920                );
 4921                anchors
 4922            });
 4923
 4924            this.change_selections(Default::default(), window, cx, |s| {
 4925                s.select_anchors(selection_anchors);
 4926            });
 4927
 4928            cx.notify();
 4929        });
 4930    }
 4931
 4932    fn trigger_completion_on_input(
 4933        &mut self,
 4934        text: &str,
 4935        trigger_in_words: bool,
 4936        window: &mut Window,
 4937        cx: &mut Context<Self>,
 4938    ) {
 4939        let completions_source = self
 4940            .context_menu
 4941            .borrow()
 4942            .as_ref()
 4943            .and_then(|menu| match menu {
 4944                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4945                CodeContextMenu::CodeActions(_) => None,
 4946            });
 4947
 4948        match completions_source {
 4949            Some(CompletionsMenuSource::Words { .. }) => {
 4950                self.open_or_update_completions_menu(
 4951                    Some(CompletionsMenuSource::Words {
 4952                        ignore_threshold: false,
 4953                    }),
 4954                    None,
 4955                    window,
 4956                    cx,
 4957                );
 4958            }
 4959            Some(CompletionsMenuSource::Normal)
 4960            | Some(CompletionsMenuSource::SnippetChoices)
 4961            | None
 4962                if self.is_completion_trigger(
 4963                    text,
 4964                    trigger_in_words,
 4965                    completions_source.is_some(),
 4966                    cx,
 4967                ) =>
 4968            {
 4969                self.show_completions(
 4970                    &ShowCompletions {
 4971                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4972                    },
 4973                    window,
 4974                    cx,
 4975                )
 4976            }
 4977            _ => {
 4978                self.hide_context_menu(window, cx);
 4979            }
 4980        }
 4981    }
 4982
 4983    fn is_completion_trigger(
 4984        &self,
 4985        text: &str,
 4986        trigger_in_words: bool,
 4987        menu_is_open: bool,
 4988        cx: &mut Context<Self>,
 4989    ) -> bool {
 4990        let position = self.selections.newest_anchor().head();
 4991        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4992            return false;
 4993        };
 4994
 4995        if let Some(completion_provider) = &self.completion_provider {
 4996            completion_provider.is_completion_trigger(
 4997                &buffer,
 4998                position.text_anchor,
 4999                text,
 5000                trigger_in_words,
 5001                menu_is_open,
 5002                cx,
 5003            )
 5004        } else {
 5005            false
 5006        }
 5007    }
 5008
 5009    /// If any empty selections is touching the start of its innermost containing autoclose
 5010    /// region, expand it to select the brackets.
 5011    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5012        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5013        let buffer = self.buffer.read(cx).read(cx);
 5014        let new_selections = self
 5015            .selections_with_autoclose_regions(selections, &buffer)
 5016            .map(|(mut selection, region)| {
 5017                if !selection.is_empty() {
 5018                    return selection;
 5019                }
 5020
 5021                if let Some(region) = region {
 5022                    let mut range = region.range.to_offset(&buffer);
 5023                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5024                        range.start -= region.pair.start.len();
 5025                        if buffer.contains_str_at(range.start, &region.pair.start)
 5026                            && buffer.contains_str_at(range.end, &region.pair.end)
 5027                        {
 5028                            range.end += region.pair.end.len();
 5029                            selection.start = range.start;
 5030                            selection.end = range.end;
 5031
 5032                            return selection;
 5033                        }
 5034                    }
 5035                }
 5036
 5037                let always_treat_brackets_as_autoclosed = buffer
 5038                    .language_settings_at(selection.start, cx)
 5039                    .always_treat_brackets_as_autoclosed;
 5040
 5041                if !always_treat_brackets_as_autoclosed {
 5042                    return selection;
 5043                }
 5044
 5045                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5046                    for (pair, enabled) in scope.brackets() {
 5047                        if !enabled || !pair.close {
 5048                            continue;
 5049                        }
 5050
 5051                        if buffer.contains_str_at(selection.start, &pair.end) {
 5052                            let pair_start_len = pair.start.len();
 5053                            if buffer.contains_str_at(
 5054                                selection.start.saturating_sub(pair_start_len),
 5055                                &pair.start,
 5056                            ) {
 5057                                selection.start -= pair_start_len;
 5058                                selection.end += pair.end.len();
 5059
 5060                                return selection;
 5061                            }
 5062                        }
 5063                    }
 5064                }
 5065
 5066                selection
 5067            })
 5068            .collect();
 5069
 5070        drop(buffer);
 5071        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5072            selections.select(new_selections)
 5073        });
 5074    }
 5075
 5076    /// Iterate the given selections, and for each one, find the smallest surrounding
 5077    /// autoclose region. This uses the ordering of the selections and the autoclose
 5078    /// regions to avoid repeated comparisons.
 5079    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5080        &'a self,
 5081        selections: impl IntoIterator<Item = Selection<D>>,
 5082        buffer: &'a MultiBufferSnapshot,
 5083    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5084        let mut i = 0;
 5085        let mut regions = self.autoclose_regions.as_slice();
 5086        selections.into_iter().map(move |selection| {
 5087            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5088
 5089            let mut enclosing = None;
 5090            while let Some(pair_state) = regions.get(i) {
 5091                if pair_state.range.end.to_offset(buffer) < range.start {
 5092                    regions = &regions[i + 1..];
 5093                    i = 0;
 5094                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5095                    break;
 5096                } else {
 5097                    if pair_state.selection_id == selection.id {
 5098                        enclosing = Some(pair_state);
 5099                    }
 5100                    i += 1;
 5101                }
 5102            }
 5103
 5104            (selection, enclosing)
 5105        })
 5106    }
 5107
 5108    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5109    fn invalidate_autoclose_regions(
 5110        &mut self,
 5111        mut selections: &[Selection<Anchor>],
 5112        buffer: &MultiBufferSnapshot,
 5113    ) {
 5114        self.autoclose_regions.retain(|state| {
 5115            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5116                return false;
 5117            }
 5118
 5119            let mut i = 0;
 5120            while let Some(selection) = selections.get(i) {
 5121                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5122                    selections = &selections[1..];
 5123                    continue;
 5124                }
 5125                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5126                    break;
 5127                }
 5128                if selection.id == state.selection_id {
 5129                    return true;
 5130                } else {
 5131                    i += 1;
 5132                }
 5133            }
 5134            false
 5135        });
 5136    }
 5137
 5138    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5139        let offset = position.to_offset(buffer);
 5140        let (word_range, kind) =
 5141            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5142        if offset > word_range.start && kind == Some(CharKind::Word) {
 5143            Some(
 5144                buffer
 5145                    .text_for_range(word_range.start..offset)
 5146                    .collect::<String>(),
 5147            )
 5148        } else {
 5149            None
 5150        }
 5151    }
 5152
 5153    pub fn visible_excerpts(
 5154        &self,
 5155        cx: &mut Context<Editor>,
 5156    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5157        let Some(project) = self.project() else {
 5158            return HashMap::default();
 5159        };
 5160        let project = project.read(cx);
 5161        let multi_buffer = self.buffer().read(cx);
 5162        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5163        let multi_buffer_visible_start = self
 5164            .scroll_manager
 5165            .anchor()
 5166            .anchor
 5167            .to_point(&multi_buffer_snapshot);
 5168        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5169            multi_buffer_visible_start
 5170                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5171            Bias::Left,
 5172        );
 5173        multi_buffer_snapshot
 5174            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5175            .into_iter()
 5176            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5177            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5178                let buffer_file = project::File::from_dyn(buffer.file())?;
 5179                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5180                let worktree_entry = buffer_worktree
 5181                    .read(cx)
 5182                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5183                if worktree_entry.is_ignored {
 5184                    None
 5185                } else {
 5186                    Some((
 5187                        excerpt_id,
 5188                        (
 5189                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5190                            buffer.version().clone(),
 5191                            excerpt_visible_range,
 5192                        ),
 5193                    ))
 5194                }
 5195            })
 5196            .collect()
 5197    }
 5198
 5199    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5200        TextLayoutDetails {
 5201            text_system: window.text_system().clone(),
 5202            editor_style: self.style.clone().unwrap(),
 5203            rem_size: window.rem_size(),
 5204            scroll_anchor: self.scroll_manager.anchor(),
 5205            visible_rows: self.visible_line_count(),
 5206            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5207        }
 5208    }
 5209
 5210    fn trigger_on_type_formatting(
 5211        &self,
 5212        input: String,
 5213        window: &mut Window,
 5214        cx: &mut Context<Self>,
 5215    ) -> Option<Task<Result<()>>> {
 5216        if input.len() != 1 {
 5217            return None;
 5218        }
 5219
 5220        let project = self.project()?;
 5221        let position = self.selections.newest_anchor().head();
 5222        let (buffer, buffer_position) = self
 5223            .buffer
 5224            .read(cx)
 5225            .text_anchor_for_position(position, cx)?;
 5226
 5227        let settings = language_settings::language_settings(
 5228            buffer
 5229                .read(cx)
 5230                .language_at(buffer_position)
 5231                .map(|l| l.name()),
 5232            buffer.read(cx).file(),
 5233            cx,
 5234        );
 5235        if !settings.use_on_type_format {
 5236            return None;
 5237        }
 5238
 5239        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5240        // hence we do LSP request & edit on host side only — add formats to host's history.
 5241        let push_to_lsp_host_history = true;
 5242        // If this is not the host, append its history with new edits.
 5243        let push_to_client_history = project.read(cx).is_via_collab();
 5244
 5245        let on_type_formatting = project.update(cx, |project, cx| {
 5246            project.on_type_format(
 5247                buffer.clone(),
 5248                buffer_position,
 5249                input,
 5250                push_to_lsp_host_history,
 5251                cx,
 5252            )
 5253        });
 5254        Some(cx.spawn_in(window, async move |editor, cx| {
 5255            if let Some(transaction) = on_type_formatting.await? {
 5256                if push_to_client_history {
 5257                    buffer
 5258                        .update(cx, |buffer, _| {
 5259                            buffer.push_transaction(transaction, Instant::now());
 5260                            buffer.finalize_last_transaction();
 5261                        })
 5262                        .ok();
 5263                }
 5264                editor.update(cx, |editor, cx| {
 5265                    editor.refresh_document_highlights(cx);
 5266                })?;
 5267            }
 5268            Ok(())
 5269        }))
 5270    }
 5271
 5272    pub fn show_word_completions(
 5273        &mut self,
 5274        _: &ShowWordCompletions,
 5275        window: &mut Window,
 5276        cx: &mut Context<Self>,
 5277    ) {
 5278        self.open_or_update_completions_menu(
 5279            Some(CompletionsMenuSource::Words {
 5280                ignore_threshold: true,
 5281            }),
 5282            None,
 5283            window,
 5284            cx,
 5285        );
 5286    }
 5287
 5288    pub fn show_completions(
 5289        &mut self,
 5290        options: &ShowCompletions,
 5291        window: &mut Window,
 5292        cx: &mut Context<Self>,
 5293    ) {
 5294        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5295    }
 5296
 5297    fn open_or_update_completions_menu(
 5298        &mut self,
 5299        requested_source: Option<CompletionsMenuSource>,
 5300        trigger: Option<&str>,
 5301        window: &mut Window,
 5302        cx: &mut Context<Self>,
 5303    ) {
 5304        if self.pending_rename.is_some() {
 5305            return;
 5306        }
 5307
 5308        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5309
 5310        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5311        // inserted and selected. To handle that case, the start of the selection is used so that
 5312        // the menu starts with all choices.
 5313        let position = self
 5314            .selections
 5315            .newest_anchor()
 5316            .start
 5317            .bias_right(&multibuffer_snapshot);
 5318        if position.diff_base_anchor.is_some() {
 5319            return;
 5320        }
 5321        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5322        let Some(buffer) = buffer_position
 5323            .buffer_id
 5324            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5325        else {
 5326            return;
 5327        };
 5328        let buffer_snapshot = buffer.read(cx).snapshot();
 5329
 5330        let query: Option<Arc<String>> =
 5331            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5332                .map(|query| query.into());
 5333
 5334        drop(multibuffer_snapshot);
 5335
 5336        // Hide the current completions menu when query is empty. Without this, cached
 5337        // completions from before the trigger char may be reused (#32774).
 5338        if query.is_none() {
 5339            let menu_is_open = matches!(
 5340                self.context_menu.borrow().as_ref(),
 5341                Some(CodeContextMenu::Completions(_))
 5342            );
 5343            if menu_is_open {
 5344                self.hide_context_menu(window, cx);
 5345            }
 5346        }
 5347
 5348        let mut ignore_word_threshold = false;
 5349        let provider = match requested_source {
 5350            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5351            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5352                ignore_word_threshold = ignore_threshold;
 5353                None
 5354            }
 5355            Some(CompletionsMenuSource::SnippetChoices) => {
 5356                log::error!("bug: SnippetChoices requested_source is not handled");
 5357                None
 5358            }
 5359        };
 5360
 5361        let sort_completions = provider
 5362            .as_ref()
 5363            .is_some_and(|provider| provider.sort_completions());
 5364
 5365        let filter_completions = provider
 5366            .as_ref()
 5367            .is_none_or(|provider| provider.filter_completions());
 5368
 5369        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5370            if filter_completions {
 5371                menu.filter(query.clone(), provider.clone(), window, cx);
 5372            }
 5373            // When `is_incomplete` is false, no need to re-query completions when the current query
 5374            // is a suffix of the initial query.
 5375            if !menu.is_incomplete {
 5376                // If the new query is a suffix of the old query (typing more characters) and
 5377                // the previous result was complete, the existing completions can be filtered.
 5378                //
 5379                // Note that this is always true for snippet completions.
 5380                let query_matches = match (&menu.initial_query, &query) {
 5381                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5382                    (None, _) => true,
 5383                    _ => false,
 5384                };
 5385                if query_matches {
 5386                    let position_matches = if menu.initial_position == position {
 5387                        true
 5388                    } else {
 5389                        let snapshot = self.buffer.read(cx).read(cx);
 5390                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5391                    };
 5392                    if position_matches {
 5393                        return;
 5394                    }
 5395                }
 5396            }
 5397        };
 5398
 5399        let trigger_kind = match trigger {
 5400            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5401                CompletionTriggerKind::TRIGGER_CHARACTER
 5402            }
 5403            _ => CompletionTriggerKind::INVOKED,
 5404        };
 5405        let completion_context = CompletionContext {
 5406            trigger_character: trigger.and_then(|trigger| {
 5407                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5408                    Some(String::from(trigger))
 5409                } else {
 5410                    None
 5411                }
 5412            }),
 5413            trigger_kind,
 5414        };
 5415
 5416        let Anchor {
 5417            excerpt_id: buffer_excerpt_id,
 5418            text_anchor: buffer_position,
 5419            ..
 5420        } = buffer_position;
 5421
 5422        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5423            buffer_snapshot.surrounding_word(buffer_position, None)
 5424        {
 5425            let word_to_exclude = buffer_snapshot
 5426                .text_for_range(word_range.clone())
 5427                .collect::<String>();
 5428            (
 5429                buffer_snapshot.anchor_before(word_range.start)
 5430                    ..buffer_snapshot.anchor_after(buffer_position),
 5431                Some(word_to_exclude),
 5432            )
 5433        } else {
 5434            (buffer_position..buffer_position, None)
 5435        };
 5436
 5437        let language = buffer_snapshot
 5438            .language_at(buffer_position)
 5439            .map(|language| language.name());
 5440
 5441        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5442            .completions
 5443            .clone();
 5444
 5445        let show_completion_documentation = buffer_snapshot
 5446            .settings_at(buffer_position, cx)
 5447            .show_completion_documentation;
 5448
 5449        // The document can be large, so stay in reasonable bounds when searching for words,
 5450        // otherwise completion pop-up might be slow to appear.
 5451        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5452        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5453        let min_word_search = buffer_snapshot.clip_point(
 5454            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5455            Bias::Left,
 5456        );
 5457        let max_word_search = buffer_snapshot.clip_point(
 5458            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5459            Bias::Right,
 5460        );
 5461        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5462            ..buffer_snapshot.point_to_offset(max_word_search);
 5463
 5464        let skip_digits = query
 5465            .as_ref()
 5466            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5467
 5468        let omit_word_completions = !self.word_completions_enabled
 5469            || (!ignore_word_threshold
 5470                && match &query {
 5471                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5472                    None => completion_settings.words_min_length != 0,
 5473                });
 5474
 5475        let (mut words, provider_responses) = match &provider {
 5476            Some(provider) => {
 5477                let provider_responses = provider.completions(
 5478                    buffer_excerpt_id,
 5479                    &buffer,
 5480                    buffer_position,
 5481                    completion_context,
 5482                    window,
 5483                    cx,
 5484                );
 5485
 5486                let words = match (omit_word_completions, completion_settings.words) {
 5487                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5488                        Task::ready(BTreeMap::default())
 5489                    }
 5490                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5491                        .background_spawn(async move {
 5492                            buffer_snapshot.words_in_range(WordsQuery {
 5493                                fuzzy_contents: None,
 5494                                range: word_search_range,
 5495                                skip_digits,
 5496                            })
 5497                        }),
 5498                };
 5499
 5500                (words, provider_responses)
 5501            }
 5502            None => {
 5503                let words = if omit_word_completions {
 5504                    Task::ready(BTreeMap::default())
 5505                } else {
 5506                    cx.background_spawn(async move {
 5507                        buffer_snapshot.words_in_range(WordsQuery {
 5508                            fuzzy_contents: None,
 5509                            range: word_search_range,
 5510                            skip_digits,
 5511                        })
 5512                    })
 5513                };
 5514                (words, Task::ready(Ok(Vec::new())))
 5515            }
 5516        };
 5517
 5518        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5519
 5520        let id = post_inc(&mut self.next_completion_id);
 5521        let task = cx.spawn_in(window, async move |editor, cx| {
 5522            let Ok(()) = editor.update(cx, |this, _| {
 5523                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5524            }) else {
 5525                return;
 5526            };
 5527
 5528            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5529            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5530            let mut completions = Vec::new();
 5531            let mut is_incomplete = false;
 5532            let mut display_options: Option<CompletionDisplayOptions> = None;
 5533            if let Some(provider_responses) = provider_responses.await.log_err()
 5534                && !provider_responses.is_empty()
 5535            {
 5536                for response in provider_responses {
 5537                    completions.extend(response.completions);
 5538                    is_incomplete = is_incomplete || response.is_incomplete;
 5539                    match display_options.as_mut() {
 5540                        None => {
 5541                            display_options = Some(response.display_options);
 5542                        }
 5543                        Some(options) => options.merge(&response.display_options),
 5544                    }
 5545                }
 5546                if completion_settings.words == WordsCompletionMode::Fallback {
 5547                    words = Task::ready(BTreeMap::default());
 5548                }
 5549            }
 5550            let display_options = display_options.unwrap_or_default();
 5551
 5552            let mut words = words.await;
 5553            if let Some(word_to_exclude) = &word_to_exclude {
 5554                words.remove(word_to_exclude);
 5555            }
 5556            for lsp_completion in &completions {
 5557                words.remove(&lsp_completion.new_text);
 5558            }
 5559            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5560                replace_range: word_replace_range.clone(),
 5561                new_text: word.clone(),
 5562                label: CodeLabel::plain(word, None),
 5563                icon_path: None,
 5564                documentation: None,
 5565                source: CompletionSource::BufferWord {
 5566                    word_range,
 5567                    resolved: false,
 5568                },
 5569                insert_text_mode: Some(InsertTextMode::AS_IS),
 5570                confirm: None,
 5571            }));
 5572
 5573            let menu = if completions.is_empty() {
 5574                None
 5575            } else {
 5576                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5577                    let languages = editor
 5578                        .workspace
 5579                        .as_ref()
 5580                        .and_then(|(workspace, _)| workspace.upgrade())
 5581                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5582                    let menu = CompletionsMenu::new(
 5583                        id,
 5584                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5585                        sort_completions,
 5586                        show_completion_documentation,
 5587                        position,
 5588                        query.clone(),
 5589                        is_incomplete,
 5590                        buffer.clone(),
 5591                        completions.into(),
 5592                        display_options,
 5593                        snippet_sort_order,
 5594                        languages,
 5595                        language,
 5596                        cx,
 5597                    );
 5598
 5599                    let query = if filter_completions { query } else { None };
 5600                    let matches_task = if let Some(query) = query {
 5601                        menu.do_async_filtering(query, cx)
 5602                    } else {
 5603                        Task::ready(menu.unfiltered_matches())
 5604                    };
 5605                    (menu, matches_task)
 5606                }) else {
 5607                    return;
 5608                };
 5609
 5610                let matches = matches_task.await;
 5611
 5612                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5613                    // Newer menu already set, so exit.
 5614                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5615                        editor.context_menu.borrow().as_ref()
 5616                        && prev_menu.id > id
 5617                    {
 5618                        return;
 5619                    };
 5620
 5621                    // Only valid to take prev_menu because it the new menu is immediately set
 5622                    // below, or the menu is hidden.
 5623                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5624                        editor.context_menu.borrow_mut().take()
 5625                    {
 5626                        let position_matches =
 5627                            if prev_menu.initial_position == menu.initial_position {
 5628                                true
 5629                            } else {
 5630                                let snapshot = editor.buffer.read(cx).read(cx);
 5631                                prev_menu.initial_position.to_offset(&snapshot)
 5632                                    == menu.initial_position.to_offset(&snapshot)
 5633                            };
 5634                        if position_matches {
 5635                            // Preserve markdown cache before `set_filter_results` because it will
 5636                            // try to populate the documentation cache.
 5637                            menu.preserve_markdown_cache(prev_menu);
 5638                        }
 5639                    };
 5640
 5641                    menu.set_filter_results(matches, provider, window, cx);
 5642                }) else {
 5643                    return;
 5644                };
 5645
 5646                menu.visible().then_some(menu)
 5647            };
 5648
 5649            editor
 5650                .update_in(cx, |editor, window, cx| {
 5651                    if editor.focus_handle.is_focused(window)
 5652                        && let Some(menu) = menu
 5653                    {
 5654                        *editor.context_menu.borrow_mut() =
 5655                            Some(CodeContextMenu::Completions(menu));
 5656
 5657                        crate::hover_popover::hide_hover(editor, cx);
 5658                        if editor.show_edit_predictions_in_menu() {
 5659                            editor.update_visible_edit_prediction(window, cx);
 5660                        } else {
 5661                            editor.discard_edit_prediction(false, cx);
 5662                        }
 5663
 5664                        cx.notify();
 5665                        return;
 5666                    }
 5667
 5668                    if editor.completion_tasks.len() <= 1 {
 5669                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5670                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5671                        // If it was already hidden and we don't show edit predictions in the menu,
 5672                        // we should also show the edit prediction when available.
 5673                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5674                            editor.update_visible_edit_prediction(window, cx);
 5675                        }
 5676                    }
 5677                })
 5678                .ok();
 5679        });
 5680
 5681        self.completion_tasks.push((id, task));
 5682    }
 5683
 5684    #[cfg(feature = "test-support")]
 5685    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5686        let menu = self.context_menu.borrow();
 5687        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5688            let completions = menu.completions.borrow();
 5689            Some(completions.to_vec())
 5690        } else {
 5691            None
 5692        }
 5693    }
 5694
 5695    pub fn with_completions_menu_matching_id<R>(
 5696        &self,
 5697        id: CompletionId,
 5698        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5699    ) -> R {
 5700        let mut context_menu = self.context_menu.borrow_mut();
 5701        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5702            return f(None);
 5703        };
 5704        if completions_menu.id != id {
 5705            return f(None);
 5706        }
 5707        f(Some(completions_menu))
 5708    }
 5709
 5710    pub fn confirm_completion(
 5711        &mut self,
 5712        action: &ConfirmCompletion,
 5713        window: &mut Window,
 5714        cx: &mut Context<Self>,
 5715    ) -> Option<Task<Result<()>>> {
 5716        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5717        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5718    }
 5719
 5720    pub fn confirm_completion_insert(
 5721        &mut self,
 5722        _: &ConfirmCompletionInsert,
 5723        window: &mut Window,
 5724        cx: &mut Context<Self>,
 5725    ) -> Option<Task<Result<()>>> {
 5726        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5727        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5728    }
 5729
 5730    pub fn confirm_completion_replace(
 5731        &mut self,
 5732        _: &ConfirmCompletionReplace,
 5733        window: &mut Window,
 5734        cx: &mut Context<Self>,
 5735    ) -> Option<Task<Result<()>>> {
 5736        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5737        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5738    }
 5739
 5740    pub fn compose_completion(
 5741        &mut self,
 5742        action: &ComposeCompletion,
 5743        window: &mut Window,
 5744        cx: &mut Context<Self>,
 5745    ) -> Option<Task<Result<()>>> {
 5746        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5747        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5748    }
 5749
 5750    fn do_completion(
 5751        &mut self,
 5752        item_ix: Option<usize>,
 5753        intent: CompletionIntent,
 5754        window: &mut Window,
 5755        cx: &mut Context<Editor>,
 5756    ) -> Option<Task<Result<()>>> {
 5757        use language::ToOffset as _;
 5758
 5759        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5760        else {
 5761            return None;
 5762        };
 5763
 5764        let candidate_id = {
 5765            let entries = completions_menu.entries.borrow();
 5766            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5767            if self.show_edit_predictions_in_menu() {
 5768                self.discard_edit_prediction(true, cx);
 5769            }
 5770            mat.candidate_id
 5771        };
 5772
 5773        let completion = completions_menu
 5774            .completions
 5775            .borrow()
 5776            .get(candidate_id)?
 5777            .clone();
 5778        cx.stop_propagation();
 5779
 5780        let buffer_handle = completions_menu.buffer.clone();
 5781
 5782        let CompletionEdit {
 5783            new_text,
 5784            snippet,
 5785            replace_range,
 5786        } = process_completion_for_edit(
 5787            &completion,
 5788            intent,
 5789            &buffer_handle,
 5790            &completions_menu.initial_position.text_anchor,
 5791            cx,
 5792        );
 5793
 5794        let buffer = buffer_handle.read(cx);
 5795        let snapshot = self.buffer.read(cx).snapshot(cx);
 5796        let newest_anchor = self.selections.newest_anchor();
 5797        let replace_range_multibuffer = {
 5798            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5799            excerpt.map_range_from_buffer(replace_range.clone())
 5800        };
 5801        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5802            return None;
 5803        }
 5804
 5805        let old_text = buffer
 5806            .text_for_range(replace_range.clone())
 5807            .collect::<String>();
 5808        let lookbehind = newest_anchor
 5809            .start
 5810            .text_anchor
 5811            .to_offset(buffer)
 5812            .saturating_sub(replace_range.start);
 5813        let lookahead = replace_range
 5814            .end
 5815            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5816        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5817        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5818
 5819        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5820        let mut ranges = Vec::new();
 5821        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5822
 5823        for selection in &selections {
 5824            let range = if selection.id == newest_anchor.id {
 5825                replace_range_multibuffer.clone()
 5826            } else {
 5827                let mut range = selection.range();
 5828
 5829                // if prefix is present, don't duplicate it
 5830                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5831                    range.start = range.start.saturating_sub(lookbehind);
 5832
 5833                    // if suffix is also present, mimic the newest cursor and replace it
 5834                    if selection.id != newest_anchor.id
 5835                        && snapshot.contains_str_at(range.end, suffix)
 5836                    {
 5837                        range.end += lookahead;
 5838                    }
 5839                }
 5840                range
 5841            };
 5842
 5843            ranges.push(range.clone());
 5844
 5845            if !self.linked_edit_ranges.is_empty() {
 5846                let start_anchor = snapshot.anchor_before(range.start);
 5847                let end_anchor = snapshot.anchor_after(range.end);
 5848                if let Some(ranges) = self
 5849                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5850                {
 5851                    for (buffer, edits) in ranges {
 5852                        linked_edits
 5853                            .entry(buffer.clone())
 5854                            .or_default()
 5855                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5856                    }
 5857                }
 5858            }
 5859        }
 5860
 5861        let common_prefix_len = old_text
 5862            .chars()
 5863            .zip(new_text.chars())
 5864            .take_while(|(a, b)| a == b)
 5865            .map(|(a, _)| a.len_utf8())
 5866            .sum::<usize>();
 5867
 5868        cx.emit(EditorEvent::InputHandled {
 5869            utf16_range_to_replace: None,
 5870            text: new_text[common_prefix_len..].into(),
 5871        });
 5872
 5873        self.transact(window, cx, |editor, window, cx| {
 5874            if let Some(mut snippet) = snippet {
 5875                snippet.text = new_text.to_string();
 5876                editor
 5877                    .insert_snippet(&ranges, snippet, window, cx)
 5878                    .log_err();
 5879            } else {
 5880                editor.buffer.update(cx, |multi_buffer, cx| {
 5881                    let auto_indent = match completion.insert_text_mode {
 5882                        Some(InsertTextMode::AS_IS) => None,
 5883                        _ => editor.autoindent_mode.clone(),
 5884                    };
 5885                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5886                    multi_buffer.edit(edits, auto_indent, cx);
 5887                });
 5888            }
 5889            for (buffer, edits) in linked_edits {
 5890                buffer.update(cx, |buffer, cx| {
 5891                    let snapshot = buffer.snapshot();
 5892                    let edits = edits
 5893                        .into_iter()
 5894                        .map(|(range, text)| {
 5895                            use text::ToPoint as TP;
 5896                            let end_point = TP::to_point(&range.end, &snapshot);
 5897                            let start_point = TP::to_point(&range.start, &snapshot);
 5898                            (start_point..end_point, text)
 5899                        })
 5900                        .sorted_by_key(|(range, _)| range.start);
 5901                    buffer.edit(edits, None, cx);
 5902                })
 5903            }
 5904
 5905            editor.refresh_edit_prediction(true, false, window, cx);
 5906        });
 5907        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 5908
 5909        let show_new_completions_on_confirm = completion
 5910            .confirm
 5911            .as_ref()
 5912            .is_some_and(|confirm| confirm(intent, window, cx));
 5913        if show_new_completions_on_confirm {
 5914            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5915        }
 5916
 5917        let provider = self.completion_provider.as_ref()?;
 5918        drop(completion);
 5919        let apply_edits = provider.apply_additional_edits_for_completion(
 5920            buffer_handle,
 5921            completions_menu.completions.clone(),
 5922            candidate_id,
 5923            true,
 5924            cx,
 5925        );
 5926
 5927        let editor_settings = EditorSettings::get_global(cx);
 5928        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5929            // After the code completion is finished, users often want to know what signatures are needed.
 5930            // so we should automatically call signature_help
 5931            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5932        }
 5933
 5934        Some(cx.foreground_executor().spawn(async move {
 5935            apply_edits.await?;
 5936            Ok(())
 5937        }))
 5938    }
 5939
 5940    pub fn toggle_code_actions(
 5941        &mut self,
 5942        action: &ToggleCodeActions,
 5943        window: &mut Window,
 5944        cx: &mut Context<Self>,
 5945    ) {
 5946        let quick_launch = action.quick_launch;
 5947        let mut context_menu = self.context_menu.borrow_mut();
 5948        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5949            if code_actions.deployed_from == action.deployed_from {
 5950                // Toggle if we're selecting the same one
 5951                *context_menu = None;
 5952                cx.notify();
 5953                return;
 5954            } else {
 5955                // Otherwise, clear it and start a new one
 5956                *context_menu = None;
 5957                cx.notify();
 5958            }
 5959        }
 5960        drop(context_menu);
 5961        let snapshot = self.snapshot(window, cx);
 5962        let deployed_from = action.deployed_from.clone();
 5963        let action = action.clone();
 5964        self.completion_tasks.clear();
 5965        self.discard_edit_prediction(false, cx);
 5966
 5967        let multibuffer_point = match &action.deployed_from {
 5968            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5969                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5970            }
 5971            _ => self
 5972                .selections
 5973                .newest::<Point>(&snapshot.display_snapshot)
 5974                .head(),
 5975        };
 5976        let Some((buffer, buffer_row)) = snapshot
 5977            .buffer_snapshot()
 5978            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5979            .and_then(|(buffer_snapshot, range)| {
 5980                self.buffer()
 5981                    .read(cx)
 5982                    .buffer(buffer_snapshot.remote_id())
 5983                    .map(|buffer| (buffer, range.start.row))
 5984            })
 5985        else {
 5986            return;
 5987        };
 5988        let buffer_id = buffer.read(cx).remote_id();
 5989        let tasks = self
 5990            .tasks
 5991            .get(&(buffer_id, buffer_row))
 5992            .map(|t| Arc::new(t.to_owned()));
 5993
 5994        if !self.focus_handle.is_focused(window) {
 5995            return;
 5996        }
 5997        let project = self.project.clone();
 5998
 5999        let code_actions_task = match deployed_from {
 6000            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6001            _ => self.code_actions(buffer_row, window, cx),
 6002        };
 6003
 6004        let runnable_task = match deployed_from {
 6005            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6006            _ => {
 6007                let mut task_context_task = Task::ready(None);
 6008                if let Some(tasks) = &tasks
 6009                    && let Some(project) = project
 6010                {
 6011                    task_context_task =
 6012                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6013                }
 6014
 6015                cx.spawn_in(window, {
 6016                    let buffer = buffer.clone();
 6017                    async move |editor, cx| {
 6018                        let task_context = task_context_task.await;
 6019
 6020                        let resolved_tasks =
 6021                            tasks
 6022                                .zip(task_context.clone())
 6023                                .map(|(tasks, task_context)| ResolvedTasks {
 6024                                    templates: tasks.resolve(&task_context).collect(),
 6025                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6026                                        multibuffer_point.row,
 6027                                        tasks.column,
 6028                                    )),
 6029                                });
 6030                        let debug_scenarios = editor
 6031                            .update(cx, |editor, cx| {
 6032                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6033                            })?
 6034                            .await;
 6035                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6036                    }
 6037                })
 6038            }
 6039        };
 6040
 6041        cx.spawn_in(window, async move |editor, cx| {
 6042            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6043            let code_actions = code_actions_task.await;
 6044            let spawn_straight_away = quick_launch
 6045                && resolved_tasks
 6046                    .as_ref()
 6047                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6048                && code_actions
 6049                    .as_ref()
 6050                    .is_none_or(|actions| actions.is_empty())
 6051                && debug_scenarios.is_empty();
 6052
 6053            editor.update_in(cx, |editor, window, cx| {
 6054                crate::hover_popover::hide_hover(editor, cx);
 6055                let actions = CodeActionContents::new(
 6056                    resolved_tasks,
 6057                    code_actions,
 6058                    debug_scenarios,
 6059                    task_context.unwrap_or_default(),
 6060                );
 6061
 6062                // Don't show the menu if there are no actions available
 6063                if actions.is_empty() {
 6064                    cx.notify();
 6065                    return Task::ready(Ok(()));
 6066                }
 6067
 6068                *editor.context_menu.borrow_mut() =
 6069                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6070                        buffer,
 6071                        actions,
 6072                        selected_item: Default::default(),
 6073                        scroll_handle: UniformListScrollHandle::default(),
 6074                        deployed_from,
 6075                    }));
 6076                cx.notify();
 6077                if spawn_straight_away
 6078                    && let Some(task) = editor.confirm_code_action(
 6079                        &ConfirmCodeAction { item_ix: Some(0) },
 6080                        window,
 6081                        cx,
 6082                    )
 6083                {
 6084                    return task;
 6085                }
 6086
 6087                Task::ready(Ok(()))
 6088            })
 6089        })
 6090        .detach_and_log_err(cx);
 6091    }
 6092
 6093    fn debug_scenarios(
 6094        &mut self,
 6095        resolved_tasks: &Option<ResolvedTasks>,
 6096        buffer: &Entity<Buffer>,
 6097        cx: &mut App,
 6098    ) -> Task<Vec<task::DebugScenario>> {
 6099        maybe!({
 6100            let project = self.project()?;
 6101            let dap_store = project.read(cx).dap_store();
 6102            let mut scenarios = vec![];
 6103            let resolved_tasks = resolved_tasks.as_ref()?;
 6104            let buffer = buffer.read(cx);
 6105            let language = buffer.language()?;
 6106            let file = buffer.file();
 6107            let debug_adapter = language_settings(language.name().into(), file, cx)
 6108                .debuggers
 6109                .first()
 6110                .map(SharedString::from)
 6111                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6112
 6113            dap_store.update(cx, |dap_store, cx| {
 6114                for (_, task) in &resolved_tasks.templates {
 6115                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6116                        task.original_task().clone(),
 6117                        debug_adapter.clone().into(),
 6118                        task.display_label().to_owned().into(),
 6119                        cx,
 6120                    );
 6121                    scenarios.push(maybe_scenario);
 6122                }
 6123            });
 6124            Some(cx.background_spawn(async move {
 6125                futures::future::join_all(scenarios)
 6126                    .await
 6127                    .into_iter()
 6128                    .flatten()
 6129                    .collect::<Vec<_>>()
 6130            }))
 6131        })
 6132        .unwrap_or_else(|| Task::ready(vec![]))
 6133    }
 6134
 6135    fn code_actions(
 6136        &mut self,
 6137        buffer_row: u32,
 6138        window: &mut Window,
 6139        cx: &mut Context<Self>,
 6140    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6141        let mut task = self.code_actions_task.take();
 6142        cx.spawn_in(window, async move |editor, cx| {
 6143            while let Some(prev_task) = task {
 6144                prev_task.await.log_err();
 6145                task = editor
 6146                    .update(cx, |this, _| this.code_actions_task.take())
 6147                    .ok()?;
 6148            }
 6149
 6150            editor
 6151                .update(cx, |editor, cx| {
 6152                    editor
 6153                        .available_code_actions
 6154                        .clone()
 6155                        .and_then(|(location, code_actions)| {
 6156                            let snapshot = location.buffer.read(cx).snapshot();
 6157                            let point_range = location.range.to_point(&snapshot);
 6158                            let point_range = point_range.start.row..=point_range.end.row;
 6159                            if point_range.contains(&buffer_row) {
 6160                                Some(code_actions)
 6161                            } else {
 6162                                None
 6163                            }
 6164                        })
 6165                })
 6166                .ok()
 6167                .flatten()
 6168        })
 6169    }
 6170
 6171    pub fn confirm_code_action(
 6172        &mut self,
 6173        action: &ConfirmCodeAction,
 6174        window: &mut Window,
 6175        cx: &mut Context<Self>,
 6176    ) -> Option<Task<Result<()>>> {
 6177        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6178
 6179        let actions_menu =
 6180            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6181                menu
 6182            } else {
 6183                return None;
 6184            };
 6185
 6186        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6187        let action = actions_menu.actions.get(action_ix)?;
 6188        let title = action.label();
 6189        let buffer = actions_menu.buffer;
 6190        let workspace = self.workspace()?;
 6191
 6192        match action {
 6193            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6194                workspace.update(cx, |workspace, cx| {
 6195                    workspace.schedule_resolved_task(
 6196                        task_source_kind,
 6197                        resolved_task,
 6198                        false,
 6199                        window,
 6200                        cx,
 6201                    );
 6202
 6203                    Some(Task::ready(Ok(())))
 6204                })
 6205            }
 6206            CodeActionsItem::CodeAction {
 6207                excerpt_id,
 6208                action,
 6209                provider,
 6210            } => {
 6211                let apply_code_action =
 6212                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6213                let workspace = workspace.downgrade();
 6214                Some(cx.spawn_in(window, async move |editor, cx| {
 6215                    let project_transaction = apply_code_action.await?;
 6216                    Self::open_project_transaction(
 6217                        &editor,
 6218                        workspace,
 6219                        project_transaction,
 6220                        title,
 6221                        cx,
 6222                    )
 6223                    .await
 6224                }))
 6225            }
 6226            CodeActionsItem::DebugScenario(scenario) => {
 6227                let context = actions_menu.actions.context;
 6228
 6229                workspace.update(cx, |workspace, cx| {
 6230                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6231                    workspace.start_debug_session(
 6232                        scenario,
 6233                        context,
 6234                        Some(buffer),
 6235                        None,
 6236                        window,
 6237                        cx,
 6238                    );
 6239                });
 6240                Some(Task::ready(Ok(())))
 6241            }
 6242        }
 6243    }
 6244
 6245    pub async fn open_project_transaction(
 6246        editor: &WeakEntity<Editor>,
 6247        workspace: WeakEntity<Workspace>,
 6248        transaction: ProjectTransaction,
 6249        title: String,
 6250        cx: &mut AsyncWindowContext,
 6251    ) -> Result<()> {
 6252        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6253        cx.update(|_, cx| {
 6254            entries.sort_unstable_by_key(|(buffer, _)| {
 6255                buffer.read(cx).file().map(|f| f.path().clone())
 6256            });
 6257        })?;
 6258        if entries.is_empty() {
 6259            return Ok(());
 6260        }
 6261
 6262        // If the project transaction's edits are all contained within this editor, then
 6263        // avoid opening a new editor to display them.
 6264
 6265        if let [(buffer, transaction)] = &*entries {
 6266            let excerpt = editor.update(cx, |editor, cx| {
 6267                editor
 6268                    .buffer()
 6269                    .read(cx)
 6270                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6271            })?;
 6272            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6273                && excerpted_buffer == *buffer
 6274            {
 6275                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6276                    let excerpt_range = excerpt_range.to_offset(buffer);
 6277                    buffer
 6278                        .edited_ranges_for_transaction::<usize>(transaction)
 6279                        .all(|range| {
 6280                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6281                        })
 6282                })?;
 6283
 6284                if all_edits_within_excerpt {
 6285                    return Ok(());
 6286                }
 6287            }
 6288        }
 6289
 6290        let mut ranges_to_highlight = Vec::new();
 6291        let excerpt_buffer = cx.new(|cx| {
 6292            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6293            for (buffer_handle, transaction) in &entries {
 6294                let edited_ranges = buffer_handle
 6295                    .read(cx)
 6296                    .edited_ranges_for_transaction::<Point>(transaction)
 6297                    .collect::<Vec<_>>();
 6298                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6299                    PathKey::for_buffer(buffer_handle, cx),
 6300                    buffer_handle.clone(),
 6301                    edited_ranges,
 6302                    multibuffer_context_lines(cx),
 6303                    cx,
 6304                );
 6305
 6306                ranges_to_highlight.extend(ranges);
 6307            }
 6308            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6309            multibuffer
 6310        })?;
 6311
 6312        workspace.update_in(cx, |workspace, window, cx| {
 6313            let project = workspace.project().clone();
 6314            let editor =
 6315                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6316            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6317            editor.update(cx, |editor, cx| {
 6318                editor.highlight_background::<Self>(
 6319                    &ranges_to_highlight,
 6320                    |theme| theme.colors().editor_highlighted_line_background,
 6321                    cx,
 6322                );
 6323            });
 6324        })?;
 6325
 6326        Ok(())
 6327    }
 6328
 6329    pub fn clear_code_action_providers(&mut self) {
 6330        self.code_action_providers.clear();
 6331        self.available_code_actions.take();
 6332    }
 6333
 6334    pub fn add_code_action_provider(
 6335        &mut self,
 6336        provider: Rc<dyn CodeActionProvider>,
 6337        window: &mut Window,
 6338        cx: &mut Context<Self>,
 6339    ) {
 6340        if self
 6341            .code_action_providers
 6342            .iter()
 6343            .any(|existing_provider| existing_provider.id() == provider.id())
 6344        {
 6345            return;
 6346        }
 6347
 6348        self.code_action_providers.push(provider);
 6349        self.refresh_code_actions(window, cx);
 6350    }
 6351
 6352    pub fn remove_code_action_provider(
 6353        &mut self,
 6354        id: Arc<str>,
 6355        window: &mut Window,
 6356        cx: &mut Context<Self>,
 6357    ) {
 6358        self.code_action_providers
 6359            .retain(|provider| provider.id() != id);
 6360        self.refresh_code_actions(window, cx);
 6361    }
 6362
 6363    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6364        !self.code_action_providers.is_empty()
 6365            && EditorSettings::get_global(cx).toolbar.code_actions
 6366    }
 6367
 6368    pub fn has_available_code_actions(&self) -> bool {
 6369        self.available_code_actions
 6370            .as_ref()
 6371            .is_some_and(|(_, actions)| !actions.is_empty())
 6372    }
 6373
 6374    fn render_inline_code_actions(
 6375        &self,
 6376        icon_size: ui::IconSize,
 6377        display_row: DisplayRow,
 6378        is_active: bool,
 6379        cx: &mut Context<Self>,
 6380    ) -> AnyElement {
 6381        let show_tooltip = !self.context_menu_visible();
 6382        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6383            .icon_size(icon_size)
 6384            .shape(ui::IconButtonShape::Square)
 6385            .icon_color(ui::Color::Hidden)
 6386            .toggle_state(is_active)
 6387            .when(show_tooltip, |this| {
 6388                this.tooltip({
 6389                    let focus_handle = self.focus_handle.clone();
 6390                    move |_window, cx| {
 6391                        Tooltip::for_action_in(
 6392                            "Toggle Code Actions",
 6393                            &ToggleCodeActions {
 6394                                deployed_from: None,
 6395                                quick_launch: false,
 6396                            },
 6397                            &focus_handle,
 6398                            cx,
 6399                        )
 6400                    }
 6401                })
 6402            })
 6403            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6404                window.focus(&editor.focus_handle(cx));
 6405                editor.toggle_code_actions(
 6406                    &crate::actions::ToggleCodeActions {
 6407                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6408                            display_row,
 6409                        )),
 6410                        quick_launch: false,
 6411                    },
 6412                    window,
 6413                    cx,
 6414                );
 6415            }))
 6416            .into_any_element()
 6417    }
 6418
 6419    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6420        &self.context_menu
 6421    }
 6422
 6423    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6424        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6425            cx.background_executor()
 6426                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6427                .await;
 6428
 6429            let (start_buffer, start, _, end, newest_selection) = this
 6430                .update(cx, |this, cx| {
 6431                    let newest_selection = this.selections.newest_anchor().clone();
 6432                    if newest_selection.head().diff_base_anchor.is_some() {
 6433                        return None;
 6434                    }
 6435                    let display_snapshot = this.display_snapshot(cx);
 6436                    let newest_selection_adjusted =
 6437                        this.selections.newest_adjusted(&display_snapshot);
 6438                    let buffer = this.buffer.read(cx);
 6439
 6440                    let (start_buffer, start) =
 6441                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6442                    let (end_buffer, end) =
 6443                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6444
 6445                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6446                })?
 6447                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6448                .context(
 6449                    "Expected selection to lie in a single buffer when refreshing code actions",
 6450                )?;
 6451            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6452                let providers = this.code_action_providers.clone();
 6453                let tasks = this
 6454                    .code_action_providers
 6455                    .iter()
 6456                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6457                    .collect::<Vec<_>>();
 6458                (providers, tasks)
 6459            })?;
 6460
 6461            let mut actions = Vec::new();
 6462            for (provider, provider_actions) in
 6463                providers.into_iter().zip(future::join_all(tasks).await)
 6464            {
 6465                if let Some(provider_actions) = provider_actions.log_err() {
 6466                    actions.extend(provider_actions.into_iter().map(|action| {
 6467                        AvailableCodeAction {
 6468                            excerpt_id: newest_selection.start.excerpt_id,
 6469                            action,
 6470                            provider: provider.clone(),
 6471                        }
 6472                    }));
 6473                }
 6474            }
 6475
 6476            this.update(cx, |this, cx| {
 6477                this.available_code_actions = if actions.is_empty() {
 6478                    None
 6479                } else {
 6480                    Some((
 6481                        Location {
 6482                            buffer: start_buffer,
 6483                            range: start..end,
 6484                        },
 6485                        actions.into(),
 6486                    ))
 6487                };
 6488                cx.notify();
 6489            })
 6490        }));
 6491    }
 6492
 6493    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6494        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6495            self.show_git_blame_inline = false;
 6496
 6497            self.show_git_blame_inline_delay_task =
 6498                Some(cx.spawn_in(window, async move |this, cx| {
 6499                    cx.background_executor().timer(delay).await;
 6500
 6501                    this.update(cx, |this, cx| {
 6502                        this.show_git_blame_inline = true;
 6503                        cx.notify();
 6504                    })
 6505                    .log_err();
 6506                }));
 6507        }
 6508    }
 6509
 6510    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6511        let snapshot = self.snapshot(window, cx);
 6512        let cursor = self
 6513            .selections
 6514            .newest::<Point>(&snapshot.display_snapshot)
 6515            .head();
 6516        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6517        else {
 6518            return;
 6519        };
 6520
 6521        let Some(blame) = self.blame.as_ref() else {
 6522            return;
 6523        };
 6524
 6525        let row_info = RowInfo {
 6526            buffer_id: Some(buffer.remote_id()),
 6527            buffer_row: Some(point.row),
 6528            ..Default::default()
 6529        };
 6530        let Some((buffer, blame_entry)) = blame
 6531            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6532            .flatten()
 6533        else {
 6534            return;
 6535        };
 6536
 6537        let anchor = self.selections.newest_anchor().head();
 6538        let position = self.to_pixel_point(anchor, &snapshot, window);
 6539        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6540            self.show_blame_popover(
 6541                buffer,
 6542                &blame_entry,
 6543                position + last_bounds.origin,
 6544                true,
 6545                cx,
 6546            );
 6547        };
 6548    }
 6549
 6550    fn show_blame_popover(
 6551        &mut self,
 6552        buffer: BufferId,
 6553        blame_entry: &BlameEntry,
 6554        position: gpui::Point<Pixels>,
 6555        ignore_timeout: bool,
 6556        cx: &mut Context<Self>,
 6557    ) {
 6558        if let Some(state) = &mut self.inline_blame_popover {
 6559            state.hide_task.take();
 6560        } else {
 6561            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6562            let blame_entry = blame_entry.clone();
 6563            let show_task = cx.spawn(async move |editor, cx| {
 6564                if !ignore_timeout {
 6565                    cx.background_executor()
 6566                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6567                        .await;
 6568                }
 6569                editor
 6570                    .update(cx, |editor, cx| {
 6571                        editor.inline_blame_popover_show_task.take();
 6572                        let Some(blame) = editor.blame.as_ref() else {
 6573                            return;
 6574                        };
 6575                        let blame = blame.read(cx);
 6576                        let details = blame.details_for_entry(buffer, &blame_entry);
 6577                        let markdown = cx.new(|cx| {
 6578                            Markdown::new(
 6579                                details
 6580                                    .as_ref()
 6581                                    .map(|message| message.message.clone())
 6582                                    .unwrap_or_default(),
 6583                                None,
 6584                                None,
 6585                                cx,
 6586                            )
 6587                        });
 6588                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6589                            position,
 6590                            hide_task: None,
 6591                            popover_bounds: None,
 6592                            popover_state: InlineBlamePopoverState {
 6593                                scroll_handle: ScrollHandle::new(),
 6594                                commit_message: details,
 6595                                markdown,
 6596                            },
 6597                            keyboard_grace: ignore_timeout,
 6598                        });
 6599                        cx.notify();
 6600                    })
 6601                    .ok();
 6602            });
 6603            self.inline_blame_popover_show_task = Some(show_task);
 6604        }
 6605    }
 6606
 6607    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6608        self.inline_blame_popover_show_task.take();
 6609        if let Some(state) = &mut self.inline_blame_popover {
 6610            let hide_task = cx.spawn(async move |editor, cx| {
 6611                if !ignore_timeout {
 6612                    cx.background_executor()
 6613                        .timer(std::time::Duration::from_millis(100))
 6614                        .await;
 6615                }
 6616                editor
 6617                    .update(cx, |editor, cx| {
 6618                        editor.inline_blame_popover.take();
 6619                        cx.notify();
 6620                    })
 6621                    .ok();
 6622            });
 6623            state.hide_task = Some(hide_task);
 6624            true
 6625        } else {
 6626            false
 6627        }
 6628    }
 6629
 6630    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6631        if self.pending_rename.is_some() {
 6632            return None;
 6633        }
 6634
 6635        let provider = self.semantics_provider.clone()?;
 6636        let buffer = self.buffer.read(cx);
 6637        let newest_selection = self.selections.newest_anchor().clone();
 6638        let cursor_position = newest_selection.head();
 6639        let (cursor_buffer, cursor_buffer_position) =
 6640            buffer.text_anchor_for_position(cursor_position, cx)?;
 6641        let (tail_buffer, tail_buffer_position) =
 6642            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6643        if cursor_buffer != tail_buffer {
 6644            return None;
 6645        }
 6646
 6647        let snapshot = cursor_buffer.read(cx).snapshot();
 6648        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6649        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6650        if start_word_range != end_word_range {
 6651            self.document_highlights_task.take();
 6652            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6653            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6654            return None;
 6655        }
 6656
 6657        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6658        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6659            cx.background_executor()
 6660                .timer(Duration::from_millis(debounce))
 6661                .await;
 6662
 6663            let highlights = if let Some(highlights) = cx
 6664                .update(|cx| {
 6665                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6666                })
 6667                .ok()
 6668                .flatten()
 6669            {
 6670                highlights.await.log_err()
 6671            } else {
 6672                None
 6673            };
 6674
 6675            if let Some(highlights) = highlights {
 6676                this.update(cx, |this, cx| {
 6677                    if this.pending_rename.is_some() {
 6678                        return;
 6679                    }
 6680
 6681                    let buffer = this.buffer.read(cx);
 6682                    if buffer
 6683                        .text_anchor_for_position(cursor_position, cx)
 6684                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6685                    {
 6686                        return;
 6687                    }
 6688
 6689                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6690                    let mut write_ranges = Vec::new();
 6691                    let mut read_ranges = Vec::new();
 6692                    for highlight in highlights {
 6693                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6694                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6695                        {
 6696                            let start = highlight
 6697                                .range
 6698                                .start
 6699                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6700                            let end = highlight
 6701                                .range
 6702                                .end
 6703                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6704                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6705                                continue;
 6706                            }
 6707
 6708                            let range =
 6709                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6710                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6711                                write_ranges.push(range);
 6712                            } else {
 6713                                read_ranges.push(range);
 6714                            }
 6715                        }
 6716                    }
 6717
 6718                    this.highlight_background::<DocumentHighlightRead>(
 6719                        &read_ranges,
 6720                        |theme| theme.colors().editor_document_highlight_read_background,
 6721                        cx,
 6722                    );
 6723                    this.highlight_background::<DocumentHighlightWrite>(
 6724                        &write_ranges,
 6725                        |theme| theme.colors().editor_document_highlight_write_background,
 6726                        cx,
 6727                    );
 6728                    cx.notify();
 6729                })
 6730                .log_err();
 6731            }
 6732        }));
 6733        None
 6734    }
 6735
 6736    fn prepare_highlight_query_from_selection(
 6737        &mut self,
 6738        window: &Window,
 6739        cx: &mut Context<Editor>,
 6740    ) -> Option<(String, Range<Anchor>)> {
 6741        if matches!(self.mode, EditorMode::SingleLine) {
 6742            return None;
 6743        }
 6744        if !EditorSettings::get_global(cx).selection_highlight {
 6745            return None;
 6746        }
 6747        if self.selections.count() != 1 || self.selections.line_mode() {
 6748            return None;
 6749        }
 6750        let snapshot = self.snapshot(window, cx);
 6751        let selection = self.selections.newest::<Point>(&snapshot);
 6752        // If the selection spans multiple rows OR it is empty
 6753        if selection.start.row != selection.end.row
 6754            || selection.start.column == selection.end.column
 6755        {
 6756            return None;
 6757        }
 6758        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6759        let query = snapshot
 6760            .buffer_snapshot()
 6761            .text_for_range(selection_anchor_range.clone())
 6762            .collect::<String>();
 6763        if query.trim().is_empty() {
 6764            return None;
 6765        }
 6766        Some((query, selection_anchor_range))
 6767    }
 6768
 6769    fn update_selection_occurrence_highlights(
 6770        &mut self,
 6771        query_text: String,
 6772        query_range: Range<Anchor>,
 6773        multi_buffer_range_to_query: Range<Point>,
 6774        use_debounce: bool,
 6775        window: &mut Window,
 6776        cx: &mut Context<Editor>,
 6777    ) -> Task<()> {
 6778        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6779        cx.spawn_in(window, async move |editor, cx| {
 6780            if use_debounce {
 6781                cx.background_executor()
 6782                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6783                    .await;
 6784            }
 6785            let match_task = cx.background_spawn(async move {
 6786                let buffer_ranges = multi_buffer_snapshot
 6787                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6788                    .into_iter()
 6789                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6790                let mut match_ranges = Vec::new();
 6791                let Ok(regex) = project::search::SearchQuery::text(
 6792                    query_text.clone(),
 6793                    false,
 6794                    false,
 6795                    false,
 6796                    Default::default(),
 6797                    Default::default(),
 6798                    false,
 6799                    None,
 6800                ) else {
 6801                    return Vec::default();
 6802                };
 6803                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6804                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6805                    match_ranges.extend(
 6806                        regex
 6807                            .search(buffer_snapshot, Some(search_range.clone()))
 6808                            .await
 6809                            .into_iter()
 6810                            .filter_map(|match_range| {
 6811                                let match_start = buffer_snapshot
 6812                                    .anchor_after(search_range.start + match_range.start);
 6813                                let match_end = buffer_snapshot
 6814                                    .anchor_before(search_range.start + match_range.end);
 6815                                let match_anchor_range = Anchor::range_in_buffer(
 6816                                    excerpt_id,
 6817                                    buffer_snapshot.remote_id(),
 6818                                    match_start..match_end,
 6819                                );
 6820                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6821                            }),
 6822                    );
 6823                }
 6824                match_ranges
 6825            });
 6826            let match_ranges = match_task.await;
 6827            editor
 6828                .update_in(cx, |editor, _, cx| {
 6829                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6830                    if !match_ranges.is_empty() {
 6831                        editor.highlight_background::<SelectedTextHighlight>(
 6832                            &match_ranges,
 6833                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6834                            cx,
 6835                        )
 6836                    }
 6837                })
 6838                .log_err();
 6839        })
 6840    }
 6841
 6842    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6843        struct NewlineFold;
 6844        let type_id = std::any::TypeId::of::<NewlineFold>();
 6845        if !self.mode.is_single_line() {
 6846            return;
 6847        }
 6848        let snapshot = self.snapshot(window, cx);
 6849        if snapshot.buffer_snapshot().max_point().row == 0 {
 6850            return;
 6851        }
 6852        let task = cx.background_spawn(async move {
 6853            let new_newlines = snapshot
 6854                .buffer_chars_at(0)
 6855                .filter_map(|(c, i)| {
 6856                    if c == '\n' {
 6857                        Some(
 6858                            snapshot.buffer_snapshot().anchor_after(i)
 6859                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6860                        )
 6861                    } else {
 6862                        None
 6863                    }
 6864                })
 6865                .collect::<Vec<_>>();
 6866            let existing_newlines = snapshot
 6867                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6868                .filter_map(|fold| {
 6869                    if fold.placeholder.type_tag == Some(type_id) {
 6870                        Some(fold.range.start..fold.range.end)
 6871                    } else {
 6872                        None
 6873                    }
 6874                })
 6875                .collect::<Vec<_>>();
 6876
 6877            (new_newlines, existing_newlines)
 6878        });
 6879        self.folding_newlines = cx.spawn(async move |this, cx| {
 6880            let (new_newlines, existing_newlines) = task.await;
 6881            if new_newlines == existing_newlines {
 6882                return;
 6883            }
 6884            let placeholder = FoldPlaceholder {
 6885                render: Arc::new(move |_, _, cx| {
 6886                    div()
 6887                        .bg(cx.theme().status().hint_background)
 6888                        .border_b_1()
 6889                        .size_full()
 6890                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6891                        .border_color(cx.theme().status().hint)
 6892                        .child("\\n")
 6893                        .into_any()
 6894                }),
 6895                constrain_width: false,
 6896                merge_adjacent: false,
 6897                type_tag: Some(type_id),
 6898            };
 6899            let creases = new_newlines
 6900                .into_iter()
 6901                .map(|range| Crease::simple(range, placeholder.clone()))
 6902                .collect();
 6903            this.update(cx, |this, cx| {
 6904                this.display_map.update(cx, |display_map, cx| {
 6905                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6906                    display_map.fold(creases, cx);
 6907                });
 6908            })
 6909            .ok();
 6910        });
 6911    }
 6912
 6913    fn refresh_selected_text_highlights(
 6914        &mut self,
 6915        on_buffer_edit: bool,
 6916        window: &mut Window,
 6917        cx: &mut Context<Editor>,
 6918    ) {
 6919        let Some((query_text, query_range)) =
 6920            self.prepare_highlight_query_from_selection(window, cx)
 6921        else {
 6922            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6923            self.quick_selection_highlight_task.take();
 6924            self.debounced_selection_highlight_task.take();
 6925            return;
 6926        };
 6927        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6928        if on_buffer_edit
 6929            || self
 6930                .quick_selection_highlight_task
 6931                .as_ref()
 6932                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6933        {
 6934            let multi_buffer_visible_start = self
 6935                .scroll_manager
 6936                .anchor()
 6937                .anchor
 6938                .to_point(&multi_buffer_snapshot);
 6939            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6940                multi_buffer_visible_start
 6941                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6942                Bias::Left,
 6943            );
 6944            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6945            self.quick_selection_highlight_task = Some((
 6946                query_range.clone(),
 6947                self.update_selection_occurrence_highlights(
 6948                    query_text.clone(),
 6949                    query_range.clone(),
 6950                    multi_buffer_visible_range,
 6951                    false,
 6952                    window,
 6953                    cx,
 6954                ),
 6955            ));
 6956        }
 6957        if on_buffer_edit
 6958            || self
 6959                .debounced_selection_highlight_task
 6960                .as_ref()
 6961                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6962        {
 6963            let multi_buffer_start = multi_buffer_snapshot
 6964                .anchor_before(0)
 6965                .to_point(&multi_buffer_snapshot);
 6966            let multi_buffer_end = multi_buffer_snapshot
 6967                .anchor_after(multi_buffer_snapshot.len())
 6968                .to_point(&multi_buffer_snapshot);
 6969            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6970            self.debounced_selection_highlight_task = Some((
 6971                query_range.clone(),
 6972                self.update_selection_occurrence_highlights(
 6973                    query_text,
 6974                    query_range,
 6975                    multi_buffer_full_range,
 6976                    true,
 6977                    window,
 6978                    cx,
 6979                ),
 6980            ));
 6981        }
 6982    }
 6983
 6984    pub fn refresh_edit_prediction(
 6985        &mut self,
 6986        debounce: bool,
 6987        user_requested: bool,
 6988        window: &mut Window,
 6989        cx: &mut Context<Self>,
 6990    ) -> Option<()> {
 6991        if DisableAiSettings::get_global(cx).disable_ai {
 6992            return None;
 6993        }
 6994
 6995        let provider = self.edit_prediction_provider()?;
 6996        let cursor = self.selections.newest_anchor().head();
 6997        let (buffer, cursor_buffer_position) =
 6998            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6999
 7000        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7001            self.discard_edit_prediction(false, cx);
 7002            return None;
 7003        }
 7004
 7005        self.update_visible_edit_prediction(window, cx);
 7006
 7007        if !user_requested
 7008            && (!self.should_show_edit_predictions()
 7009                || !self.is_focused(window)
 7010                || buffer.read(cx).is_empty())
 7011        {
 7012            self.discard_edit_prediction(false, cx);
 7013            return None;
 7014        }
 7015
 7016        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7017        Some(())
 7018    }
 7019
 7020    fn show_edit_predictions_in_menu(&self) -> bool {
 7021        match self.edit_prediction_settings {
 7022            EditPredictionSettings::Disabled => false,
 7023            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7024        }
 7025    }
 7026
 7027    pub fn edit_predictions_enabled(&self) -> bool {
 7028        match self.edit_prediction_settings {
 7029            EditPredictionSettings::Disabled => false,
 7030            EditPredictionSettings::Enabled { .. } => true,
 7031        }
 7032    }
 7033
 7034    fn edit_prediction_requires_modifier(&self) -> bool {
 7035        match self.edit_prediction_settings {
 7036            EditPredictionSettings::Disabled => false,
 7037            EditPredictionSettings::Enabled {
 7038                preview_requires_modifier,
 7039                ..
 7040            } => preview_requires_modifier,
 7041        }
 7042    }
 7043
 7044    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7045        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7046            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7047            self.discard_edit_prediction(false, cx);
 7048        } else {
 7049            let selection = self.selections.newest_anchor();
 7050            let cursor = selection.head();
 7051
 7052            if let Some((buffer, cursor_buffer_position)) =
 7053                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7054            {
 7055                self.edit_prediction_settings =
 7056                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7057            }
 7058        }
 7059    }
 7060
 7061    fn edit_prediction_settings_at_position(
 7062        &self,
 7063        buffer: &Entity<Buffer>,
 7064        buffer_position: language::Anchor,
 7065        cx: &App,
 7066    ) -> EditPredictionSettings {
 7067        if !self.mode.is_full()
 7068            || !self.show_edit_predictions_override.unwrap_or(true)
 7069            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7070        {
 7071            return EditPredictionSettings::Disabled;
 7072        }
 7073
 7074        let buffer = buffer.read(cx);
 7075
 7076        let file = buffer.file();
 7077
 7078        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7079            return EditPredictionSettings::Disabled;
 7080        };
 7081
 7082        let by_provider = matches!(
 7083            self.menu_edit_predictions_policy,
 7084            MenuEditPredictionsPolicy::ByProvider
 7085        );
 7086
 7087        let show_in_menu = by_provider
 7088            && self
 7089                .edit_prediction_provider
 7090                .as_ref()
 7091                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7092
 7093        let preview_requires_modifier =
 7094            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7095
 7096        EditPredictionSettings::Enabled {
 7097            show_in_menu,
 7098            preview_requires_modifier,
 7099        }
 7100    }
 7101
 7102    fn should_show_edit_predictions(&self) -> bool {
 7103        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7104    }
 7105
 7106    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7107        matches!(
 7108            self.edit_prediction_preview,
 7109            EditPredictionPreview::Active { .. }
 7110        )
 7111    }
 7112
 7113    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7114        let cursor = self.selections.newest_anchor().head();
 7115        if let Some((buffer, cursor_position)) =
 7116            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7117        {
 7118            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7119        } else {
 7120            false
 7121        }
 7122    }
 7123
 7124    pub fn supports_minimap(&self, cx: &App) -> bool {
 7125        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7126    }
 7127
 7128    fn edit_predictions_enabled_in_buffer(
 7129        &self,
 7130        buffer: &Entity<Buffer>,
 7131        buffer_position: language::Anchor,
 7132        cx: &App,
 7133    ) -> bool {
 7134        maybe!({
 7135            if self.read_only(cx) {
 7136                return Some(false);
 7137            }
 7138            let provider = self.edit_prediction_provider()?;
 7139            if !provider.is_enabled(buffer, buffer_position, cx) {
 7140                return Some(false);
 7141            }
 7142            let buffer = buffer.read(cx);
 7143            let Some(file) = buffer.file() else {
 7144                return Some(true);
 7145            };
 7146            let settings = all_language_settings(Some(file), cx);
 7147            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7148        })
 7149        .unwrap_or(false)
 7150    }
 7151
 7152    fn cycle_edit_prediction(
 7153        &mut self,
 7154        direction: Direction,
 7155        window: &mut Window,
 7156        cx: &mut Context<Self>,
 7157    ) -> Option<()> {
 7158        let provider = self.edit_prediction_provider()?;
 7159        let cursor = self.selections.newest_anchor().head();
 7160        let (buffer, cursor_buffer_position) =
 7161            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7162        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7163            return None;
 7164        }
 7165
 7166        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7167        self.update_visible_edit_prediction(window, cx);
 7168
 7169        Some(())
 7170    }
 7171
 7172    pub fn show_edit_prediction(
 7173        &mut self,
 7174        _: &ShowEditPrediction,
 7175        window: &mut Window,
 7176        cx: &mut Context<Self>,
 7177    ) {
 7178        if !self.has_active_edit_prediction() {
 7179            self.refresh_edit_prediction(false, true, window, cx);
 7180            return;
 7181        }
 7182
 7183        self.update_visible_edit_prediction(window, cx);
 7184    }
 7185
 7186    pub fn display_cursor_names(
 7187        &mut self,
 7188        _: &DisplayCursorNames,
 7189        window: &mut Window,
 7190        cx: &mut Context<Self>,
 7191    ) {
 7192        self.show_cursor_names(window, cx);
 7193    }
 7194
 7195    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7196        self.show_cursor_names = true;
 7197        cx.notify();
 7198        cx.spawn_in(window, async move |this, cx| {
 7199            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7200            this.update(cx, |this, cx| {
 7201                this.show_cursor_names = false;
 7202                cx.notify()
 7203            })
 7204            .ok()
 7205        })
 7206        .detach();
 7207    }
 7208
 7209    pub fn next_edit_prediction(
 7210        &mut self,
 7211        _: &NextEditPrediction,
 7212        window: &mut Window,
 7213        cx: &mut Context<Self>,
 7214    ) {
 7215        if self.has_active_edit_prediction() {
 7216            self.cycle_edit_prediction(Direction::Next, window, cx);
 7217        } else {
 7218            let is_copilot_disabled = self
 7219                .refresh_edit_prediction(false, true, window, cx)
 7220                .is_none();
 7221            if is_copilot_disabled {
 7222                cx.propagate();
 7223            }
 7224        }
 7225    }
 7226
 7227    pub fn previous_edit_prediction(
 7228        &mut self,
 7229        _: &PreviousEditPrediction,
 7230        window: &mut Window,
 7231        cx: &mut Context<Self>,
 7232    ) {
 7233        if self.has_active_edit_prediction() {
 7234            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7235        } else {
 7236            let is_copilot_disabled = self
 7237                .refresh_edit_prediction(false, true, window, cx)
 7238                .is_none();
 7239            if is_copilot_disabled {
 7240                cx.propagate();
 7241            }
 7242        }
 7243    }
 7244
 7245    pub fn accept_edit_prediction(
 7246        &mut self,
 7247        _: &AcceptEditPrediction,
 7248        window: &mut Window,
 7249        cx: &mut Context<Self>,
 7250    ) {
 7251        if self.show_edit_predictions_in_menu() {
 7252            self.hide_context_menu(window, cx);
 7253        }
 7254
 7255        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7256            return;
 7257        };
 7258
 7259        match &active_edit_prediction.completion {
 7260            EditPrediction::MoveWithin { target, .. } => {
 7261                let target = *target;
 7262
 7263                if let Some(position_map) = &self.last_position_map {
 7264                    if position_map
 7265                        .visible_row_range
 7266                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7267                        || !self.edit_prediction_requires_modifier()
 7268                    {
 7269                        self.unfold_ranges(&[target..target], true, false, cx);
 7270                        // Note that this is also done in vim's handler of the Tab action.
 7271                        self.change_selections(
 7272                            SelectionEffects::scroll(Autoscroll::newest()),
 7273                            window,
 7274                            cx,
 7275                            |selections| {
 7276                                selections.select_anchor_ranges([target..target]);
 7277                            },
 7278                        );
 7279                        self.clear_row_highlights::<EditPredictionPreview>();
 7280
 7281                        self.edit_prediction_preview
 7282                            .set_previous_scroll_position(None);
 7283                    } else {
 7284                        self.edit_prediction_preview
 7285                            .set_previous_scroll_position(Some(
 7286                                position_map.snapshot.scroll_anchor,
 7287                            ));
 7288
 7289                        self.highlight_rows::<EditPredictionPreview>(
 7290                            target..target,
 7291                            cx.theme().colors().editor_highlighted_line_background,
 7292                            RowHighlightOptions {
 7293                                autoscroll: true,
 7294                                ..Default::default()
 7295                            },
 7296                            cx,
 7297                        );
 7298                        self.request_autoscroll(Autoscroll::fit(), cx);
 7299                    }
 7300                }
 7301            }
 7302            EditPrediction::MoveOutside { snapshot, target } => {
 7303                if let Some(workspace) = self.workspace() {
 7304                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7305                        .detach_and_log_err(cx);
 7306                }
 7307            }
 7308            EditPrediction::Edit { edits, .. } => {
 7309                self.report_edit_prediction_event(
 7310                    active_edit_prediction.completion_id.clone(),
 7311                    true,
 7312                    cx,
 7313                );
 7314
 7315                if let Some(provider) = self.edit_prediction_provider() {
 7316                    provider.accept(cx);
 7317                }
 7318
 7319                // Store the transaction ID and selections before applying the edit
 7320                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7321
 7322                let snapshot = self.buffer.read(cx).snapshot(cx);
 7323                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7324
 7325                self.buffer.update(cx, |buffer, cx| {
 7326                    buffer.edit(edits.iter().cloned(), None, cx)
 7327                });
 7328
 7329                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7330                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7331                });
 7332
 7333                let selections = self.selections.disjoint_anchors_arc();
 7334                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7335                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7336                    if has_new_transaction {
 7337                        self.selection_history
 7338                            .insert_transaction(transaction_id_now, selections);
 7339                    }
 7340                }
 7341
 7342                self.update_visible_edit_prediction(window, cx);
 7343                if self.active_edit_prediction.is_none() {
 7344                    self.refresh_edit_prediction(true, true, window, cx);
 7345                }
 7346
 7347                cx.notify();
 7348            }
 7349        }
 7350
 7351        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7352    }
 7353
 7354    pub fn accept_partial_edit_prediction(
 7355        &mut self,
 7356        _: &AcceptPartialEditPrediction,
 7357        window: &mut Window,
 7358        cx: &mut Context<Self>,
 7359    ) {
 7360        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7361            return;
 7362        };
 7363        if self.selections.count() != 1 {
 7364            return;
 7365        }
 7366
 7367        match &active_edit_prediction.completion {
 7368            EditPrediction::MoveWithin { target, .. } => {
 7369                let target = *target;
 7370                self.change_selections(
 7371                    SelectionEffects::scroll(Autoscroll::newest()),
 7372                    window,
 7373                    cx,
 7374                    |selections| {
 7375                        selections.select_anchor_ranges([target..target]);
 7376                    },
 7377                );
 7378            }
 7379            EditPrediction::MoveOutside { snapshot, target } => {
 7380                if let Some(workspace) = self.workspace() {
 7381                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7382                        .detach_and_log_err(cx);
 7383                }
 7384            }
 7385            EditPrediction::Edit { edits, .. } => {
 7386                self.report_edit_prediction_event(
 7387                    active_edit_prediction.completion_id.clone(),
 7388                    true,
 7389                    cx,
 7390                );
 7391
 7392                // Find an insertion that starts at the cursor position.
 7393                let snapshot = self.buffer.read(cx).snapshot(cx);
 7394                let cursor_offset = self
 7395                    .selections
 7396                    .newest::<usize>(&self.display_snapshot(cx))
 7397                    .head();
 7398                let insertion = edits.iter().find_map(|(range, text)| {
 7399                    let range = range.to_offset(&snapshot);
 7400                    if range.is_empty() && range.start == cursor_offset {
 7401                        Some(text)
 7402                    } else {
 7403                        None
 7404                    }
 7405                });
 7406
 7407                if let Some(text) = insertion {
 7408                    let mut partial_completion = text
 7409                        .chars()
 7410                        .by_ref()
 7411                        .take_while(|c| c.is_alphabetic())
 7412                        .collect::<String>();
 7413                    if partial_completion.is_empty() {
 7414                        partial_completion = text
 7415                            .chars()
 7416                            .by_ref()
 7417                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7418                            .collect::<String>();
 7419                    }
 7420
 7421                    cx.emit(EditorEvent::InputHandled {
 7422                        utf16_range_to_replace: None,
 7423                        text: partial_completion.clone().into(),
 7424                    });
 7425
 7426                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7427
 7428                    self.refresh_edit_prediction(true, true, window, cx);
 7429                    cx.notify();
 7430                } else {
 7431                    self.accept_edit_prediction(&Default::default(), window, cx);
 7432                }
 7433            }
 7434        }
 7435    }
 7436
 7437    fn discard_edit_prediction(
 7438        &mut self,
 7439        should_report_edit_prediction_event: bool,
 7440        cx: &mut Context<Self>,
 7441    ) -> bool {
 7442        if should_report_edit_prediction_event {
 7443            let completion_id = self
 7444                .active_edit_prediction
 7445                .as_ref()
 7446                .and_then(|active_completion| active_completion.completion_id.clone());
 7447
 7448            self.report_edit_prediction_event(completion_id, false, cx);
 7449        }
 7450
 7451        if let Some(provider) = self.edit_prediction_provider() {
 7452            provider.discard(cx);
 7453        }
 7454
 7455        self.take_active_edit_prediction(cx)
 7456    }
 7457
 7458    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7459        let Some(provider) = self.edit_prediction_provider() else {
 7460            return;
 7461        };
 7462
 7463        let Some((_, buffer, _)) = self
 7464            .buffer
 7465            .read(cx)
 7466            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7467        else {
 7468            return;
 7469        };
 7470
 7471        let extension = buffer
 7472            .read(cx)
 7473            .file()
 7474            .and_then(|file| Some(file.path().extension()?.to_string()));
 7475
 7476        let event_type = match accepted {
 7477            true => "Edit Prediction Accepted",
 7478            false => "Edit Prediction Discarded",
 7479        };
 7480        telemetry::event!(
 7481            event_type,
 7482            provider = provider.name(),
 7483            prediction_id = id,
 7484            suggestion_accepted = accepted,
 7485            file_extension = extension,
 7486        );
 7487    }
 7488
 7489    fn open_editor_at_anchor(
 7490        snapshot: &language::BufferSnapshot,
 7491        target: language::Anchor,
 7492        workspace: &Entity<Workspace>,
 7493        window: &mut Window,
 7494        cx: &mut App,
 7495    ) -> Task<Result<()>> {
 7496        workspace.update(cx, |workspace, cx| {
 7497            let path = snapshot.file().map(|file| file.full_path(cx));
 7498            let Some(path) =
 7499                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7500            else {
 7501                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7502            };
 7503            let target = text::ToPoint::to_point(&target, snapshot);
 7504            let item = workspace.open_path(path, None, true, window, cx);
 7505            window.spawn(cx, async move |cx| {
 7506                let Some(editor) = item.await?.downcast::<Editor>() else {
 7507                    return Ok(());
 7508                };
 7509                editor
 7510                    .update_in(cx, |editor, window, cx| {
 7511                        editor.go_to_singleton_buffer_point(target, window, cx);
 7512                    })
 7513                    .ok();
 7514                anyhow::Ok(())
 7515            })
 7516        })
 7517    }
 7518
 7519    pub fn has_active_edit_prediction(&self) -> bool {
 7520        self.active_edit_prediction.is_some()
 7521    }
 7522
 7523    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7524        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7525            return false;
 7526        };
 7527
 7528        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7529        self.clear_highlights::<EditPredictionHighlight>(cx);
 7530        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7531        true
 7532    }
 7533
 7534    /// Returns true when we're displaying the edit prediction popover below the cursor
 7535    /// like we are not previewing and the LSP autocomplete menu is visible
 7536    /// or we are in `when_holding_modifier` mode.
 7537    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7538        if self.edit_prediction_preview_is_active()
 7539            || !self.show_edit_predictions_in_menu()
 7540            || !self.edit_predictions_enabled()
 7541        {
 7542            return false;
 7543        }
 7544
 7545        if self.has_visible_completions_menu() {
 7546            return true;
 7547        }
 7548
 7549        has_completion && self.edit_prediction_requires_modifier()
 7550    }
 7551
 7552    fn handle_modifiers_changed(
 7553        &mut self,
 7554        modifiers: Modifiers,
 7555        position_map: &PositionMap,
 7556        window: &mut Window,
 7557        cx: &mut Context<Self>,
 7558    ) {
 7559        if self.show_edit_predictions_in_menu() {
 7560            self.update_edit_prediction_preview(&modifiers, window, cx);
 7561        }
 7562
 7563        self.update_selection_mode(&modifiers, position_map, window, cx);
 7564
 7565        let mouse_position = window.mouse_position();
 7566        if !position_map.text_hitbox.is_hovered(window) {
 7567            return;
 7568        }
 7569
 7570        self.update_hovered_link(
 7571            position_map.point_for_position(mouse_position),
 7572            &position_map.snapshot,
 7573            modifiers,
 7574            window,
 7575            cx,
 7576        )
 7577    }
 7578
 7579    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7580        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7581        if invert {
 7582            match multi_cursor_setting {
 7583                MultiCursorModifier::Alt => modifiers.alt,
 7584                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7585            }
 7586        } else {
 7587            match multi_cursor_setting {
 7588                MultiCursorModifier::Alt => modifiers.secondary(),
 7589                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7590            }
 7591        }
 7592    }
 7593
 7594    fn columnar_selection_mode(
 7595        modifiers: &Modifiers,
 7596        cx: &mut Context<Self>,
 7597    ) -> Option<ColumnarMode> {
 7598        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7599            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7600                Some(ColumnarMode::FromMouse)
 7601            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7602                Some(ColumnarMode::FromSelection)
 7603            } else {
 7604                None
 7605            }
 7606        } else {
 7607            None
 7608        }
 7609    }
 7610
 7611    fn update_selection_mode(
 7612        &mut self,
 7613        modifiers: &Modifiers,
 7614        position_map: &PositionMap,
 7615        window: &mut Window,
 7616        cx: &mut Context<Self>,
 7617    ) {
 7618        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7619            return;
 7620        };
 7621        if self.selections.pending_anchor().is_none() {
 7622            return;
 7623        }
 7624
 7625        let mouse_position = window.mouse_position();
 7626        let point_for_position = position_map.point_for_position(mouse_position);
 7627        let position = point_for_position.previous_valid;
 7628
 7629        self.select(
 7630            SelectPhase::BeginColumnar {
 7631                position,
 7632                reset: false,
 7633                mode,
 7634                goal_column: point_for_position.exact_unclipped.column(),
 7635            },
 7636            window,
 7637            cx,
 7638        );
 7639    }
 7640
 7641    fn update_edit_prediction_preview(
 7642        &mut self,
 7643        modifiers: &Modifiers,
 7644        window: &mut Window,
 7645        cx: &mut Context<Self>,
 7646    ) {
 7647        let mut modifiers_held = false;
 7648        if let Some(accept_keystroke) = self
 7649            .accept_edit_prediction_keybind(false, window, cx)
 7650            .keystroke()
 7651        {
 7652            modifiers_held = modifiers_held
 7653                || (accept_keystroke.modifiers() == modifiers
 7654                    && accept_keystroke.modifiers().modified());
 7655        };
 7656        if let Some(accept_partial_keystroke) = self
 7657            .accept_edit_prediction_keybind(true, window, cx)
 7658            .keystroke()
 7659        {
 7660            modifiers_held = modifiers_held
 7661                || (accept_partial_keystroke.modifiers() == modifiers
 7662                    && accept_partial_keystroke.modifiers().modified());
 7663        }
 7664
 7665        if modifiers_held {
 7666            if matches!(
 7667                self.edit_prediction_preview,
 7668                EditPredictionPreview::Inactive { .. }
 7669            ) {
 7670                self.edit_prediction_preview = EditPredictionPreview::Active {
 7671                    previous_scroll_position: None,
 7672                    since: Instant::now(),
 7673                };
 7674
 7675                self.update_visible_edit_prediction(window, cx);
 7676                cx.notify();
 7677            }
 7678        } else if let EditPredictionPreview::Active {
 7679            previous_scroll_position,
 7680            since,
 7681        } = self.edit_prediction_preview
 7682        {
 7683            if let (Some(previous_scroll_position), Some(position_map)) =
 7684                (previous_scroll_position, self.last_position_map.as_ref())
 7685            {
 7686                self.set_scroll_position(
 7687                    previous_scroll_position
 7688                        .scroll_position(&position_map.snapshot.display_snapshot),
 7689                    window,
 7690                    cx,
 7691                );
 7692            }
 7693
 7694            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7695                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7696            };
 7697            self.clear_row_highlights::<EditPredictionPreview>();
 7698            self.update_visible_edit_prediction(window, cx);
 7699            cx.notify();
 7700        }
 7701    }
 7702
 7703    fn update_visible_edit_prediction(
 7704        &mut self,
 7705        _window: &mut Window,
 7706        cx: &mut Context<Self>,
 7707    ) -> Option<()> {
 7708        if DisableAiSettings::get_global(cx).disable_ai {
 7709            return None;
 7710        }
 7711
 7712        if self.ime_transaction.is_some() {
 7713            self.discard_edit_prediction(false, cx);
 7714            return None;
 7715        }
 7716
 7717        let selection = self.selections.newest_anchor();
 7718        let cursor = selection.head();
 7719        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7720        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7721        let excerpt_id = cursor.excerpt_id;
 7722
 7723        let show_in_menu = self.show_edit_predictions_in_menu();
 7724        let completions_menu_has_precedence = !show_in_menu
 7725            && (self.context_menu.borrow().is_some()
 7726                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7727
 7728        if completions_menu_has_precedence
 7729            || !offset_selection.is_empty()
 7730            || self
 7731                .active_edit_prediction
 7732                .as_ref()
 7733                .is_some_and(|completion| {
 7734                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7735                        return false;
 7736                    };
 7737                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7738                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7739                    !invalidation_range.contains(&offset_selection.head())
 7740                })
 7741        {
 7742            self.discard_edit_prediction(false, cx);
 7743            return None;
 7744        }
 7745
 7746        self.take_active_edit_prediction(cx);
 7747        let Some(provider) = self.edit_prediction_provider() else {
 7748            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7749            return None;
 7750        };
 7751
 7752        let (buffer, cursor_buffer_position) =
 7753            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7754
 7755        self.edit_prediction_settings =
 7756            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7757
 7758        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7759
 7760        if self.edit_prediction_indent_conflict {
 7761            let cursor_point = cursor.to_point(&multibuffer);
 7762
 7763            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7764
 7765            if let Some((_, indent)) = indents.iter().next()
 7766                && indent.len == cursor_point.column
 7767            {
 7768                self.edit_prediction_indent_conflict = false;
 7769            }
 7770        }
 7771
 7772        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7773
 7774        let (completion_id, edits, edit_preview) = match edit_prediction {
 7775            edit_prediction::EditPrediction::Local {
 7776                id,
 7777                edits,
 7778                edit_preview,
 7779            } => (id, edits, edit_preview),
 7780            edit_prediction::EditPrediction::Jump {
 7781                id,
 7782                snapshot,
 7783                target,
 7784            } => {
 7785                self.stale_edit_prediction_in_menu = None;
 7786                self.active_edit_prediction = Some(EditPredictionState {
 7787                    inlay_ids: vec![],
 7788                    completion: EditPrediction::MoveOutside { snapshot, target },
 7789                    completion_id: id,
 7790                    invalidation_range: None,
 7791                });
 7792                cx.notify();
 7793                return Some(());
 7794            }
 7795        };
 7796
 7797        let edits = edits
 7798            .into_iter()
 7799            .flat_map(|(range, new_text)| {
 7800                Some((
 7801                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7802                    new_text,
 7803                ))
 7804            })
 7805            .collect::<Vec<_>>();
 7806        if edits.is_empty() {
 7807            return None;
 7808        }
 7809
 7810        let first_edit_start = edits.first().unwrap().0.start;
 7811        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7812        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7813
 7814        let last_edit_end = edits.last().unwrap().0.end;
 7815        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7816        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7817
 7818        let cursor_row = cursor.to_point(&multibuffer).row;
 7819
 7820        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7821
 7822        let mut inlay_ids = Vec::new();
 7823        let invalidation_row_range;
 7824        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7825            Some(cursor_row..edit_end_row)
 7826        } else if cursor_row > edit_end_row {
 7827            Some(edit_start_row..cursor_row)
 7828        } else {
 7829            None
 7830        };
 7831        let supports_jump = self
 7832            .edit_prediction_provider
 7833            .as_ref()
 7834            .map(|provider| provider.provider.supports_jump_to_edit())
 7835            .unwrap_or(true);
 7836
 7837        let is_move = supports_jump
 7838            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7839        let completion = if is_move {
 7840            invalidation_row_range =
 7841                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7842            let target = first_edit_start;
 7843            EditPrediction::MoveWithin { target, snapshot }
 7844        } else {
 7845            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7846                && !self.edit_predictions_hidden_for_vim_mode;
 7847
 7848            if show_completions_in_buffer {
 7849                if edits
 7850                    .iter()
 7851                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7852                {
 7853                    let mut inlays = Vec::new();
 7854                    for (range, new_text) in &edits {
 7855                        let inlay = Inlay::edit_prediction(
 7856                            post_inc(&mut self.next_inlay_id),
 7857                            range.start,
 7858                            new_text.as_str(),
 7859                        );
 7860                        inlay_ids.push(inlay.id);
 7861                        inlays.push(inlay);
 7862                    }
 7863
 7864                    self.splice_inlays(&[], inlays, cx);
 7865                } else {
 7866                    let background_color = cx.theme().status().deleted_background;
 7867                    self.highlight_text::<EditPredictionHighlight>(
 7868                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7869                        HighlightStyle {
 7870                            background_color: Some(background_color),
 7871                            ..Default::default()
 7872                        },
 7873                        cx,
 7874                    );
 7875                }
 7876            }
 7877
 7878            invalidation_row_range = edit_start_row..edit_end_row;
 7879
 7880            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7881                if provider.show_tab_accept_marker() {
 7882                    EditDisplayMode::TabAccept
 7883                } else {
 7884                    EditDisplayMode::Inline
 7885                }
 7886            } else {
 7887                EditDisplayMode::DiffPopover
 7888            };
 7889
 7890            EditPrediction::Edit {
 7891                edits,
 7892                edit_preview,
 7893                display_mode,
 7894                snapshot,
 7895            }
 7896        };
 7897
 7898        let invalidation_range = multibuffer
 7899            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7900            ..multibuffer.anchor_after(Point::new(
 7901                invalidation_row_range.end,
 7902                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7903            ));
 7904
 7905        self.stale_edit_prediction_in_menu = None;
 7906        self.active_edit_prediction = Some(EditPredictionState {
 7907            inlay_ids,
 7908            completion,
 7909            completion_id,
 7910            invalidation_range: Some(invalidation_range),
 7911        });
 7912
 7913        cx.notify();
 7914
 7915        Some(())
 7916    }
 7917
 7918    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7919        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7920    }
 7921
 7922    fn clear_tasks(&mut self) {
 7923        self.tasks.clear()
 7924    }
 7925
 7926    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7927        if self.tasks.insert(key, value).is_some() {
 7928            // This case should hopefully be rare, but just in case...
 7929            log::error!(
 7930                "multiple different run targets found on a single line, only the last target will be rendered"
 7931            )
 7932        }
 7933    }
 7934
 7935    /// Get all display points of breakpoints that will be rendered within editor
 7936    ///
 7937    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7938    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7939    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7940    fn active_breakpoints(
 7941        &self,
 7942        range: Range<DisplayRow>,
 7943        window: &mut Window,
 7944        cx: &mut Context<Self>,
 7945    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7946        let mut breakpoint_display_points = HashMap::default();
 7947
 7948        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7949            return breakpoint_display_points;
 7950        };
 7951
 7952        let snapshot = self.snapshot(window, cx);
 7953
 7954        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 7955        let Some(project) = self.project() else {
 7956            return breakpoint_display_points;
 7957        };
 7958
 7959        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7960            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7961
 7962        for (buffer_snapshot, range, excerpt_id) in
 7963            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7964        {
 7965            let Some(buffer) = project
 7966                .read(cx)
 7967                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7968            else {
 7969                continue;
 7970            };
 7971            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7972                &buffer,
 7973                Some(
 7974                    buffer_snapshot.anchor_before(range.start)
 7975                        ..buffer_snapshot.anchor_after(range.end),
 7976                ),
 7977                buffer_snapshot,
 7978                cx,
 7979            );
 7980            for (breakpoint, state) in breakpoints {
 7981                let multi_buffer_anchor =
 7982                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7983                let position = multi_buffer_anchor
 7984                    .to_point(&multi_buffer_snapshot)
 7985                    .to_display_point(&snapshot);
 7986
 7987                breakpoint_display_points.insert(
 7988                    position.row(),
 7989                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7990                );
 7991            }
 7992        }
 7993
 7994        breakpoint_display_points
 7995    }
 7996
 7997    fn breakpoint_context_menu(
 7998        &self,
 7999        anchor: Anchor,
 8000        window: &mut Window,
 8001        cx: &mut Context<Self>,
 8002    ) -> Entity<ui::ContextMenu> {
 8003        let weak_editor = cx.weak_entity();
 8004        let focus_handle = self.focus_handle(cx);
 8005
 8006        let row = self
 8007            .buffer
 8008            .read(cx)
 8009            .snapshot(cx)
 8010            .summary_for_anchor::<Point>(&anchor)
 8011            .row;
 8012
 8013        let breakpoint = self
 8014            .breakpoint_at_row(row, window, cx)
 8015            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8016
 8017        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8018            "Edit Log Breakpoint"
 8019        } else {
 8020            "Set Log Breakpoint"
 8021        };
 8022
 8023        let condition_breakpoint_msg = if breakpoint
 8024            .as_ref()
 8025            .is_some_and(|bp| bp.1.condition.is_some())
 8026        {
 8027            "Edit Condition Breakpoint"
 8028        } else {
 8029            "Set Condition Breakpoint"
 8030        };
 8031
 8032        let hit_condition_breakpoint_msg = if breakpoint
 8033            .as_ref()
 8034            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8035        {
 8036            "Edit Hit Condition Breakpoint"
 8037        } else {
 8038            "Set Hit Condition Breakpoint"
 8039        };
 8040
 8041        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8042            "Unset Breakpoint"
 8043        } else {
 8044            "Set Breakpoint"
 8045        };
 8046
 8047        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8048
 8049        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8050            BreakpointState::Enabled => Some("Disable"),
 8051            BreakpointState::Disabled => Some("Enable"),
 8052        });
 8053
 8054        let (anchor, breakpoint) =
 8055            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8056
 8057        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8058            menu.on_blur_subscription(Subscription::new(|| {}))
 8059                .context(focus_handle)
 8060                .when(run_to_cursor, |this| {
 8061                    let weak_editor = weak_editor.clone();
 8062                    this.entry("Run to cursor", None, move |window, cx| {
 8063                        weak_editor
 8064                            .update(cx, |editor, cx| {
 8065                                editor.change_selections(
 8066                                    SelectionEffects::no_scroll(),
 8067                                    window,
 8068                                    cx,
 8069                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8070                                );
 8071                            })
 8072                            .ok();
 8073
 8074                        window.dispatch_action(Box::new(RunToCursor), cx);
 8075                    })
 8076                    .separator()
 8077                })
 8078                .when_some(toggle_state_msg, |this, msg| {
 8079                    this.entry(msg, None, {
 8080                        let weak_editor = weak_editor.clone();
 8081                        let breakpoint = breakpoint.clone();
 8082                        move |_window, cx| {
 8083                            weak_editor
 8084                                .update(cx, |this, cx| {
 8085                                    this.edit_breakpoint_at_anchor(
 8086                                        anchor,
 8087                                        breakpoint.as_ref().clone(),
 8088                                        BreakpointEditAction::InvertState,
 8089                                        cx,
 8090                                    );
 8091                                })
 8092                                .log_err();
 8093                        }
 8094                    })
 8095                })
 8096                .entry(set_breakpoint_msg, None, {
 8097                    let weak_editor = weak_editor.clone();
 8098                    let breakpoint = breakpoint.clone();
 8099                    move |_window, cx| {
 8100                        weak_editor
 8101                            .update(cx, |this, cx| {
 8102                                this.edit_breakpoint_at_anchor(
 8103                                    anchor,
 8104                                    breakpoint.as_ref().clone(),
 8105                                    BreakpointEditAction::Toggle,
 8106                                    cx,
 8107                                );
 8108                            })
 8109                            .log_err();
 8110                    }
 8111                })
 8112                .entry(log_breakpoint_msg, None, {
 8113                    let breakpoint = breakpoint.clone();
 8114                    let weak_editor = weak_editor.clone();
 8115                    move |window, cx| {
 8116                        weak_editor
 8117                            .update(cx, |this, cx| {
 8118                                this.add_edit_breakpoint_block(
 8119                                    anchor,
 8120                                    breakpoint.as_ref(),
 8121                                    BreakpointPromptEditAction::Log,
 8122                                    window,
 8123                                    cx,
 8124                                );
 8125                            })
 8126                            .log_err();
 8127                    }
 8128                })
 8129                .entry(condition_breakpoint_msg, None, {
 8130                    let breakpoint = breakpoint.clone();
 8131                    let weak_editor = weak_editor.clone();
 8132                    move |window, cx| {
 8133                        weak_editor
 8134                            .update(cx, |this, cx| {
 8135                                this.add_edit_breakpoint_block(
 8136                                    anchor,
 8137                                    breakpoint.as_ref(),
 8138                                    BreakpointPromptEditAction::Condition,
 8139                                    window,
 8140                                    cx,
 8141                                );
 8142                            })
 8143                            .log_err();
 8144                    }
 8145                })
 8146                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8147                    weak_editor
 8148                        .update(cx, |this, cx| {
 8149                            this.add_edit_breakpoint_block(
 8150                                anchor,
 8151                                breakpoint.as_ref(),
 8152                                BreakpointPromptEditAction::HitCondition,
 8153                                window,
 8154                                cx,
 8155                            );
 8156                        })
 8157                        .log_err();
 8158                })
 8159        })
 8160    }
 8161
 8162    fn render_breakpoint(
 8163        &self,
 8164        position: Anchor,
 8165        row: DisplayRow,
 8166        breakpoint: &Breakpoint,
 8167        state: Option<BreakpointSessionState>,
 8168        cx: &mut Context<Self>,
 8169    ) -> IconButton {
 8170        let is_rejected = state.is_some_and(|s| !s.verified);
 8171        // Is it a breakpoint that shows up when hovering over gutter?
 8172        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8173            (false, false),
 8174            |PhantomBreakpointIndicator {
 8175                 is_active,
 8176                 display_row,
 8177                 collides_with_existing_breakpoint,
 8178             }| {
 8179                (
 8180                    is_active && display_row == row,
 8181                    collides_with_existing_breakpoint,
 8182                )
 8183            },
 8184        );
 8185
 8186        let (color, icon) = {
 8187            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8188                (false, false) => ui::IconName::DebugBreakpoint,
 8189                (true, false) => ui::IconName::DebugLogBreakpoint,
 8190                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8191                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8192            };
 8193
 8194            let color = if is_phantom {
 8195                Color::Hint
 8196            } else if is_rejected {
 8197                Color::Disabled
 8198            } else {
 8199                Color::Debugger
 8200            };
 8201
 8202            (color, icon)
 8203        };
 8204
 8205        let breakpoint = Arc::from(breakpoint.clone());
 8206
 8207        let alt_as_text = gpui::Keystroke {
 8208            modifiers: Modifiers::secondary_key(),
 8209            ..Default::default()
 8210        };
 8211        let primary_action_text = if breakpoint.is_disabled() {
 8212            "Enable breakpoint"
 8213        } else if is_phantom && !collides_with_existing {
 8214            "Set breakpoint"
 8215        } else {
 8216            "Unset breakpoint"
 8217        };
 8218        let focus_handle = self.focus_handle.clone();
 8219
 8220        let meta = if is_rejected {
 8221            SharedString::from("No executable code is associated with this line.")
 8222        } else if collides_with_existing && !breakpoint.is_disabled() {
 8223            SharedString::from(format!(
 8224                "{alt_as_text}-click to disable,\nright-click for more options."
 8225            ))
 8226        } else {
 8227            SharedString::from("Right-click for more options.")
 8228        };
 8229        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8230            .icon_size(IconSize::XSmall)
 8231            .size(ui::ButtonSize::None)
 8232            .when(is_rejected, |this| {
 8233                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8234            })
 8235            .icon_color(color)
 8236            .style(ButtonStyle::Transparent)
 8237            .on_click(cx.listener({
 8238                move |editor, event: &ClickEvent, window, cx| {
 8239                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8240                        BreakpointEditAction::InvertState
 8241                    } else {
 8242                        BreakpointEditAction::Toggle
 8243                    };
 8244
 8245                    window.focus(&editor.focus_handle(cx));
 8246                    editor.edit_breakpoint_at_anchor(
 8247                        position,
 8248                        breakpoint.as_ref().clone(),
 8249                        edit_action,
 8250                        cx,
 8251                    );
 8252                }
 8253            }))
 8254            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8255                editor.set_breakpoint_context_menu(
 8256                    row,
 8257                    Some(position),
 8258                    event.position(),
 8259                    window,
 8260                    cx,
 8261                );
 8262            }))
 8263            .tooltip(move |_window, cx| {
 8264                Tooltip::with_meta_in(
 8265                    primary_action_text,
 8266                    Some(&ToggleBreakpoint),
 8267                    meta.clone(),
 8268                    &focus_handle,
 8269                    cx,
 8270                )
 8271            })
 8272    }
 8273
 8274    fn build_tasks_context(
 8275        project: &Entity<Project>,
 8276        buffer: &Entity<Buffer>,
 8277        buffer_row: u32,
 8278        tasks: &Arc<RunnableTasks>,
 8279        cx: &mut Context<Self>,
 8280    ) -> Task<Option<task::TaskContext>> {
 8281        let position = Point::new(buffer_row, tasks.column);
 8282        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8283        let location = Location {
 8284            buffer: buffer.clone(),
 8285            range: range_start..range_start,
 8286        };
 8287        // Fill in the environmental variables from the tree-sitter captures
 8288        let mut captured_task_variables = TaskVariables::default();
 8289        for (capture_name, value) in tasks.extra_variables.clone() {
 8290            captured_task_variables.insert(
 8291                task::VariableName::Custom(capture_name.into()),
 8292                value.clone(),
 8293            );
 8294        }
 8295        project.update(cx, |project, cx| {
 8296            project.task_store().update(cx, |task_store, cx| {
 8297                task_store.task_context_for_location(captured_task_variables, location, cx)
 8298            })
 8299        })
 8300    }
 8301
 8302    pub fn spawn_nearest_task(
 8303        &mut self,
 8304        action: &SpawnNearestTask,
 8305        window: &mut Window,
 8306        cx: &mut Context<Self>,
 8307    ) {
 8308        let Some((workspace, _)) = self.workspace.clone() else {
 8309            return;
 8310        };
 8311        let Some(project) = self.project.clone() else {
 8312            return;
 8313        };
 8314
 8315        // Try to find a closest, enclosing node using tree-sitter that has a task
 8316        let Some((buffer, buffer_row, tasks)) = self
 8317            .find_enclosing_node_task(cx)
 8318            // Or find the task that's closest in row-distance.
 8319            .or_else(|| self.find_closest_task(cx))
 8320        else {
 8321            return;
 8322        };
 8323
 8324        let reveal_strategy = action.reveal;
 8325        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8326        cx.spawn_in(window, async move |_, cx| {
 8327            let context = task_context.await?;
 8328            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8329
 8330            let resolved = &mut resolved_task.resolved;
 8331            resolved.reveal = reveal_strategy;
 8332
 8333            workspace
 8334                .update_in(cx, |workspace, window, cx| {
 8335                    workspace.schedule_resolved_task(
 8336                        task_source_kind,
 8337                        resolved_task,
 8338                        false,
 8339                        window,
 8340                        cx,
 8341                    );
 8342                })
 8343                .ok()
 8344        })
 8345        .detach();
 8346    }
 8347
 8348    fn find_closest_task(
 8349        &mut self,
 8350        cx: &mut Context<Self>,
 8351    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8352        let cursor_row = self
 8353            .selections
 8354            .newest_adjusted(&self.display_snapshot(cx))
 8355            .head()
 8356            .row;
 8357
 8358        let ((buffer_id, row), tasks) = self
 8359            .tasks
 8360            .iter()
 8361            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8362
 8363        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8364        let tasks = Arc::new(tasks.to_owned());
 8365        Some((buffer, *row, tasks))
 8366    }
 8367
 8368    fn find_enclosing_node_task(
 8369        &mut self,
 8370        cx: &mut Context<Self>,
 8371    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8372        let snapshot = self.buffer.read(cx).snapshot(cx);
 8373        let offset = self
 8374            .selections
 8375            .newest::<usize>(&self.display_snapshot(cx))
 8376            .head();
 8377        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8378        let buffer_id = excerpt.buffer().remote_id();
 8379
 8380        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8381        let mut cursor = layer.node().walk();
 8382
 8383        while cursor.goto_first_child_for_byte(offset).is_some() {
 8384            if cursor.node().end_byte() == offset {
 8385                cursor.goto_next_sibling();
 8386            }
 8387        }
 8388
 8389        // Ascend to the smallest ancestor that contains the range and has a task.
 8390        loop {
 8391            let node = cursor.node();
 8392            let node_range = node.byte_range();
 8393            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8394
 8395            // Check if this node contains our offset
 8396            if node_range.start <= offset && node_range.end >= offset {
 8397                // If it contains offset, check for task
 8398                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8399                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8400                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8401                }
 8402            }
 8403
 8404            if !cursor.goto_parent() {
 8405                break;
 8406            }
 8407        }
 8408        None
 8409    }
 8410
 8411    fn render_run_indicator(
 8412        &self,
 8413        _style: &EditorStyle,
 8414        is_active: bool,
 8415        row: DisplayRow,
 8416        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8417        cx: &mut Context<Self>,
 8418    ) -> IconButton {
 8419        let color = Color::Muted;
 8420        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8421
 8422        IconButton::new(
 8423            ("run_indicator", row.0 as usize),
 8424            ui::IconName::PlayOutlined,
 8425        )
 8426        .shape(ui::IconButtonShape::Square)
 8427        .icon_size(IconSize::XSmall)
 8428        .icon_color(color)
 8429        .toggle_state(is_active)
 8430        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8431            let quick_launch = match e {
 8432                ClickEvent::Keyboard(_) => true,
 8433                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8434            };
 8435
 8436            window.focus(&editor.focus_handle(cx));
 8437            editor.toggle_code_actions(
 8438                &ToggleCodeActions {
 8439                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8440                    quick_launch,
 8441                },
 8442                window,
 8443                cx,
 8444            );
 8445        }))
 8446        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8447            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8448        }))
 8449    }
 8450
 8451    pub fn context_menu_visible(&self) -> bool {
 8452        !self.edit_prediction_preview_is_active()
 8453            && self
 8454                .context_menu
 8455                .borrow()
 8456                .as_ref()
 8457                .is_some_and(|menu| menu.visible())
 8458    }
 8459
 8460    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8461        self.context_menu
 8462            .borrow()
 8463            .as_ref()
 8464            .map(|menu| menu.origin())
 8465    }
 8466
 8467    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8468        self.context_menu_options = Some(options);
 8469    }
 8470
 8471    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8472    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8473
 8474    fn render_edit_prediction_popover(
 8475        &mut self,
 8476        text_bounds: &Bounds<Pixels>,
 8477        content_origin: gpui::Point<Pixels>,
 8478        right_margin: Pixels,
 8479        editor_snapshot: &EditorSnapshot,
 8480        visible_row_range: Range<DisplayRow>,
 8481        scroll_top: ScrollOffset,
 8482        scroll_bottom: ScrollOffset,
 8483        line_layouts: &[LineWithInvisibles],
 8484        line_height: Pixels,
 8485        scroll_position: gpui::Point<ScrollOffset>,
 8486        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8487        newest_selection_head: Option<DisplayPoint>,
 8488        editor_width: Pixels,
 8489        style: &EditorStyle,
 8490        window: &mut Window,
 8491        cx: &mut App,
 8492    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8493        if self.mode().is_minimap() {
 8494            return None;
 8495        }
 8496        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8497
 8498        if self.edit_prediction_visible_in_cursor_popover(true) {
 8499            return None;
 8500        }
 8501
 8502        match &active_edit_prediction.completion {
 8503            EditPrediction::MoveWithin { target, .. } => {
 8504                let target_display_point = target.to_display_point(editor_snapshot);
 8505
 8506                if self.edit_prediction_requires_modifier() {
 8507                    if !self.edit_prediction_preview_is_active() {
 8508                        return None;
 8509                    }
 8510
 8511                    self.render_edit_prediction_modifier_jump_popover(
 8512                        text_bounds,
 8513                        content_origin,
 8514                        visible_row_range,
 8515                        line_layouts,
 8516                        line_height,
 8517                        scroll_pixel_position,
 8518                        newest_selection_head,
 8519                        target_display_point,
 8520                        window,
 8521                        cx,
 8522                    )
 8523                } else {
 8524                    self.render_edit_prediction_eager_jump_popover(
 8525                        text_bounds,
 8526                        content_origin,
 8527                        editor_snapshot,
 8528                        visible_row_range,
 8529                        scroll_top,
 8530                        scroll_bottom,
 8531                        line_height,
 8532                        scroll_pixel_position,
 8533                        target_display_point,
 8534                        editor_width,
 8535                        window,
 8536                        cx,
 8537                    )
 8538                }
 8539            }
 8540            EditPrediction::Edit {
 8541                display_mode: EditDisplayMode::Inline,
 8542                ..
 8543            } => None,
 8544            EditPrediction::Edit {
 8545                display_mode: EditDisplayMode::TabAccept,
 8546                edits,
 8547                ..
 8548            } => {
 8549                let range = &edits.first()?.0;
 8550                let target_display_point = range.end.to_display_point(editor_snapshot);
 8551
 8552                self.render_edit_prediction_end_of_line_popover(
 8553                    "Accept",
 8554                    editor_snapshot,
 8555                    visible_row_range,
 8556                    target_display_point,
 8557                    line_height,
 8558                    scroll_pixel_position,
 8559                    content_origin,
 8560                    editor_width,
 8561                    window,
 8562                    cx,
 8563                )
 8564            }
 8565            EditPrediction::Edit {
 8566                edits,
 8567                edit_preview,
 8568                display_mode: EditDisplayMode::DiffPopover,
 8569                snapshot,
 8570            } => self.render_edit_prediction_diff_popover(
 8571                text_bounds,
 8572                content_origin,
 8573                right_margin,
 8574                editor_snapshot,
 8575                visible_row_range,
 8576                line_layouts,
 8577                line_height,
 8578                scroll_position,
 8579                scroll_pixel_position,
 8580                newest_selection_head,
 8581                editor_width,
 8582                style,
 8583                edits,
 8584                edit_preview,
 8585                snapshot,
 8586                window,
 8587                cx,
 8588            ),
 8589            EditPrediction::MoveOutside { snapshot, .. } => {
 8590                let file_name = snapshot
 8591                    .file()
 8592                    .map(|file| file.file_name(cx))
 8593                    .unwrap_or("untitled");
 8594                let mut element = self
 8595                    .render_edit_prediction_line_popover(
 8596                        format!("Jump to {file_name}"),
 8597                        Some(IconName::ZedPredict),
 8598                        window,
 8599                        cx,
 8600                    )
 8601                    .into_any();
 8602
 8603                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8604                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8605                let origin_y = text_bounds.size.height - size.height - px(30.);
 8606                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8607                element.prepaint_at(origin, window, cx);
 8608
 8609                Some((element, origin))
 8610            }
 8611        }
 8612    }
 8613
 8614    fn render_edit_prediction_modifier_jump_popover(
 8615        &mut self,
 8616        text_bounds: &Bounds<Pixels>,
 8617        content_origin: gpui::Point<Pixels>,
 8618        visible_row_range: Range<DisplayRow>,
 8619        line_layouts: &[LineWithInvisibles],
 8620        line_height: Pixels,
 8621        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8622        newest_selection_head: Option<DisplayPoint>,
 8623        target_display_point: DisplayPoint,
 8624        window: &mut Window,
 8625        cx: &mut App,
 8626    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8627        let scrolled_content_origin =
 8628            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8629
 8630        const SCROLL_PADDING_Y: Pixels = px(12.);
 8631
 8632        if target_display_point.row() < visible_row_range.start {
 8633            return self.render_edit_prediction_scroll_popover(
 8634                |_| SCROLL_PADDING_Y,
 8635                IconName::ArrowUp,
 8636                visible_row_range,
 8637                line_layouts,
 8638                newest_selection_head,
 8639                scrolled_content_origin,
 8640                window,
 8641                cx,
 8642            );
 8643        } else if target_display_point.row() >= visible_row_range.end {
 8644            return self.render_edit_prediction_scroll_popover(
 8645                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8646                IconName::ArrowDown,
 8647                visible_row_range,
 8648                line_layouts,
 8649                newest_selection_head,
 8650                scrolled_content_origin,
 8651                window,
 8652                cx,
 8653            );
 8654        }
 8655
 8656        const POLE_WIDTH: Pixels = px(2.);
 8657
 8658        let line_layout =
 8659            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8660        let target_column = target_display_point.column() as usize;
 8661
 8662        let target_x = line_layout.x_for_index(target_column);
 8663        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8664            - scroll_pixel_position.y;
 8665
 8666        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8667
 8668        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8669        border_color.l += 0.001;
 8670
 8671        let mut element = v_flex()
 8672            .items_end()
 8673            .when(flag_on_right, |el| el.items_start())
 8674            .child(if flag_on_right {
 8675                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8676                    .rounded_bl(px(0.))
 8677                    .rounded_tl(px(0.))
 8678                    .border_l_2()
 8679                    .border_color(border_color)
 8680            } else {
 8681                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8682                    .rounded_br(px(0.))
 8683                    .rounded_tr(px(0.))
 8684                    .border_r_2()
 8685                    .border_color(border_color)
 8686            })
 8687            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8688            .into_any();
 8689
 8690        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8691
 8692        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8693            - point(
 8694                if flag_on_right {
 8695                    POLE_WIDTH
 8696                } else {
 8697                    size.width - POLE_WIDTH
 8698                },
 8699                size.height - line_height,
 8700            );
 8701
 8702        origin.x = origin.x.max(content_origin.x);
 8703
 8704        element.prepaint_at(origin, window, cx);
 8705
 8706        Some((element, origin))
 8707    }
 8708
 8709    fn render_edit_prediction_scroll_popover(
 8710        &mut self,
 8711        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8712        scroll_icon: IconName,
 8713        visible_row_range: Range<DisplayRow>,
 8714        line_layouts: &[LineWithInvisibles],
 8715        newest_selection_head: Option<DisplayPoint>,
 8716        scrolled_content_origin: gpui::Point<Pixels>,
 8717        window: &mut Window,
 8718        cx: &mut App,
 8719    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8720        let mut element = self
 8721            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8722            .into_any();
 8723
 8724        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8725
 8726        let cursor = newest_selection_head?;
 8727        let cursor_row_layout =
 8728            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8729        let cursor_column = cursor.column() as usize;
 8730
 8731        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8732
 8733        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8734
 8735        element.prepaint_at(origin, window, cx);
 8736        Some((element, origin))
 8737    }
 8738
 8739    fn render_edit_prediction_eager_jump_popover(
 8740        &mut self,
 8741        text_bounds: &Bounds<Pixels>,
 8742        content_origin: gpui::Point<Pixels>,
 8743        editor_snapshot: &EditorSnapshot,
 8744        visible_row_range: Range<DisplayRow>,
 8745        scroll_top: ScrollOffset,
 8746        scroll_bottom: ScrollOffset,
 8747        line_height: Pixels,
 8748        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8749        target_display_point: DisplayPoint,
 8750        editor_width: Pixels,
 8751        window: &mut Window,
 8752        cx: &mut App,
 8753    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8754        if target_display_point.row().as_f64() < scroll_top {
 8755            let mut element = self
 8756                .render_edit_prediction_line_popover(
 8757                    "Jump to Edit",
 8758                    Some(IconName::ArrowUp),
 8759                    window,
 8760                    cx,
 8761                )
 8762                .into_any();
 8763
 8764            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8765            let offset = point(
 8766                (text_bounds.size.width - size.width) / 2.,
 8767                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8768            );
 8769
 8770            let origin = text_bounds.origin + offset;
 8771            element.prepaint_at(origin, window, cx);
 8772            Some((element, origin))
 8773        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8774            let mut element = self
 8775                .render_edit_prediction_line_popover(
 8776                    "Jump to Edit",
 8777                    Some(IconName::ArrowDown),
 8778                    window,
 8779                    cx,
 8780                )
 8781                .into_any();
 8782
 8783            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8784            let offset = point(
 8785                (text_bounds.size.width - size.width) / 2.,
 8786                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8787            );
 8788
 8789            let origin = text_bounds.origin + offset;
 8790            element.prepaint_at(origin, window, cx);
 8791            Some((element, origin))
 8792        } else {
 8793            self.render_edit_prediction_end_of_line_popover(
 8794                "Jump to Edit",
 8795                editor_snapshot,
 8796                visible_row_range,
 8797                target_display_point,
 8798                line_height,
 8799                scroll_pixel_position,
 8800                content_origin,
 8801                editor_width,
 8802                window,
 8803                cx,
 8804            )
 8805        }
 8806    }
 8807
 8808    fn render_edit_prediction_end_of_line_popover(
 8809        self: &mut Editor,
 8810        label: &'static str,
 8811        editor_snapshot: &EditorSnapshot,
 8812        visible_row_range: Range<DisplayRow>,
 8813        target_display_point: DisplayPoint,
 8814        line_height: Pixels,
 8815        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8816        content_origin: gpui::Point<Pixels>,
 8817        editor_width: Pixels,
 8818        window: &mut Window,
 8819        cx: &mut App,
 8820    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8821        let target_line_end = DisplayPoint::new(
 8822            target_display_point.row(),
 8823            editor_snapshot.line_len(target_display_point.row()),
 8824        );
 8825
 8826        let mut element = self
 8827            .render_edit_prediction_line_popover(label, None, window, cx)
 8828            .into_any();
 8829
 8830        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8831
 8832        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8833
 8834        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8835        let mut origin = start_point
 8836            + line_origin
 8837            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8838        origin.x = origin.x.max(content_origin.x);
 8839
 8840        let max_x = content_origin.x + editor_width - size.width;
 8841
 8842        if origin.x > max_x {
 8843            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8844
 8845            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8846                origin.y += offset;
 8847                IconName::ArrowUp
 8848            } else {
 8849                origin.y -= offset;
 8850                IconName::ArrowDown
 8851            };
 8852
 8853            element = self
 8854                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8855                .into_any();
 8856
 8857            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8858
 8859            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8860        }
 8861
 8862        element.prepaint_at(origin, window, cx);
 8863        Some((element, origin))
 8864    }
 8865
 8866    fn render_edit_prediction_diff_popover(
 8867        self: &Editor,
 8868        text_bounds: &Bounds<Pixels>,
 8869        content_origin: gpui::Point<Pixels>,
 8870        right_margin: Pixels,
 8871        editor_snapshot: &EditorSnapshot,
 8872        visible_row_range: Range<DisplayRow>,
 8873        line_layouts: &[LineWithInvisibles],
 8874        line_height: Pixels,
 8875        scroll_position: gpui::Point<ScrollOffset>,
 8876        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8877        newest_selection_head: Option<DisplayPoint>,
 8878        editor_width: Pixels,
 8879        style: &EditorStyle,
 8880        edits: &Vec<(Range<Anchor>, String)>,
 8881        edit_preview: &Option<language::EditPreview>,
 8882        snapshot: &language::BufferSnapshot,
 8883        window: &mut Window,
 8884        cx: &mut App,
 8885    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8886        let edit_start = edits
 8887            .first()
 8888            .unwrap()
 8889            .0
 8890            .start
 8891            .to_display_point(editor_snapshot);
 8892        let edit_end = edits
 8893            .last()
 8894            .unwrap()
 8895            .0
 8896            .end
 8897            .to_display_point(editor_snapshot);
 8898
 8899        let is_visible = visible_row_range.contains(&edit_start.row())
 8900            || visible_row_range.contains(&edit_end.row());
 8901        if !is_visible {
 8902            return None;
 8903        }
 8904
 8905        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8906            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8907        } else {
 8908            // Fallback for providers without edit_preview
 8909            crate::edit_prediction_fallback_text(edits, cx)
 8910        };
 8911
 8912        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8913        let line_count = highlighted_edits.text.lines().count();
 8914
 8915        const BORDER_WIDTH: Pixels = px(1.);
 8916
 8917        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8918        let has_keybind = keybind.is_some();
 8919
 8920        let mut element = h_flex()
 8921            .items_start()
 8922            .child(
 8923                h_flex()
 8924                    .bg(cx.theme().colors().editor_background)
 8925                    .border(BORDER_WIDTH)
 8926                    .shadow_xs()
 8927                    .border_color(cx.theme().colors().border)
 8928                    .rounded_l_lg()
 8929                    .when(line_count > 1, |el| el.rounded_br_lg())
 8930                    .pr_1()
 8931                    .child(styled_text),
 8932            )
 8933            .child(
 8934                h_flex()
 8935                    .h(line_height + BORDER_WIDTH * 2.)
 8936                    .px_1p5()
 8937                    .gap_1()
 8938                    // Workaround: For some reason, there's a gap if we don't do this
 8939                    .ml(-BORDER_WIDTH)
 8940                    .shadow(vec![gpui::BoxShadow {
 8941                        color: gpui::black().opacity(0.05),
 8942                        offset: point(px(1.), px(1.)),
 8943                        blur_radius: px(2.),
 8944                        spread_radius: px(0.),
 8945                    }])
 8946                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8947                    .border(BORDER_WIDTH)
 8948                    .border_color(cx.theme().colors().border)
 8949                    .rounded_r_lg()
 8950                    .id("edit_prediction_diff_popover_keybind")
 8951                    .when(!has_keybind, |el| {
 8952                        let status_colors = cx.theme().status();
 8953
 8954                        el.bg(status_colors.error_background)
 8955                            .border_color(status_colors.error.opacity(0.6))
 8956                            .child(Icon::new(IconName::Info).color(Color::Error))
 8957                            .cursor_default()
 8958                            .hoverable_tooltip(move |_window, cx| {
 8959                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8960                            })
 8961                    })
 8962                    .children(keybind),
 8963            )
 8964            .into_any();
 8965
 8966        let longest_row =
 8967            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8968        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8969            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8970        } else {
 8971            layout_line(
 8972                longest_row,
 8973                editor_snapshot,
 8974                style,
 8975                editor_width,
 8976                |_| false,
 8977                window,
 8978                cx,
 8979            )
 8980            .width
 8981        };
 8982
 8983        let viewport_bounds =
 8984            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8985                right: -right_margin,
 8986                ..Default::default()
 8987            });
 8988
 8989        let x_after_longest = Pixels::from(
 8990            ScrollPixelOffset::from(
 8991                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 8992            ) - scroll_pixel_position.x,
 8993        );
 8994
 8995        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8996
 8997        // Fully visible if it can be displayed within the window (allow overlapping other
 8998        // panes). However, this is only allowed if the popover starts within text_bounds.
 8999        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9000            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9001
 9002        let mut origin = if can_position_to_the_right {
 9003            point(
 9004                x_after_longest,
 9005                text_bounds.origin.y
 9006                    + Pixels::from(
 9007                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9008                            - scroll_pixel_position.y,
 9009                    ),
 9010            )
 9011        } else {
 9012            let cursor_row = newest_selection_head.map(|head| head.row());
 9013            let above_edit = edit_start
 9014                .row()
 9015                .0
 9016                .checked_sub(line_count as u32)
 9017                .map(DisplayRow);
 9018            let below_edit = Some(edit_end.row() + 1);
 9019            let above_cursor =
 9020                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9021            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9022
 9023            // Place the edit popover adjacent to the edit if there is a location
 9024            // available that is onscreen and does not obscure the cursor. Otherwise,
 9025            // place it adjacent to the cursor.
 9026            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9027                .into_iter()
 9028                .flatten()
 9029                .find(|&start_row| {
 9030                    let end_row = start_row + line_count as u32;
 9031                    visible_row_range.contains(&start_row)
 9032                        && visible_row_range.contains(&end_row)
 9033                        && cursor_row
 9034                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9035                })?;
 9036
 9037            content_origin
 9038                + point(
 9039                    Pixels::from(-scroll_pixel_position.x),
 9040                    Pixels::from(
 9041                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9042                    ),
 9043                )
 9044        };
 9045
 9046        origin.x -= BORDER_WIDTH;
 9047
 9048        window.defer_draw(element, origin, 1);
 9049
 9050        // Do not return an element, since it will already be drawn due to defer_draw.
 9051        None
 9052    }
 9053
 9054    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9055        px(30.)
 9056    }
 9057
 9058    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9059        if self.read_only(cx) {
 9060            cx.theme().players().read_only()
 9061        } else {
 9062            self.style.as_ref().unwrap().local_player
 9063        }
 9064    }
 9065
 9066    fn render_edit_prediction_accept_keybind(
 9067        &self,
 9068        window: &mut Window,
 9069        cx: &mut App,
 9070    ) -> Option<AnyElement> {
 9071        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9072        let accept_keystroke = accept_binding.keystroke()?;
 9073
 9074        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9075
 9076        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9077            Color::Accent
 9078        } else {
 9079            Color::Muted
 9080        };
 9081
 9082        h_flex()
 9083            .px_0p5()
 9084            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9085            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9086            .text_size(TextSize::XSmall.rems(cx))
 9087            .child(h_flex().children(ui::render_modifiers(
 9088                accept_keystroke.modifiers(),
 9089                PlatformStyle::platform(),
 9090                Some(modifiers_color),
 9091                Some(IconSize::XSmall.rems().into()),
 9092                true,
 9093            )))
 9094            .when(is_platform_style_mac, |parent| {
 9095                parent.child(accept_keystroke.key().to_string())
 9096            })
 9097            .when(!is_platform_style_mac, |parent| {
 9098                parent.child(
 9099                    Key::new(
 9100                        util::capitalize(accept_keystroke.key()),
 9101                        Some(Color::Default),
 9102                    )
 9103                    .size(Some(IconSize::XSmall.rems().into())),
 9104                )
 9105            })
 9106            .into_any()
 9107            .into()
 9108    }
 9109
 9110    fn render_edit_prediction_line_popover(
 9111        &self,
 9112        label: impl Into<SharedString>,
 9113        icon: Option<IconName>,
 9114        window: &mut Window,
 9115        cx: &mut App,
 9116    ) -> Stateful<Div> {
 9117        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9118
 9119        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9120        let has_keybind = keybind.is_some();
 9121
 9122        h_flex()
 9123            .id("ep-line-popover")
 9124            .py_0p5()
 9125            .pl_1()
 9126            .pr(padding_right)
 9127            .gap_1()
 9128            .rounded_md()
 9129            .border_1()
 9130            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9131            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9132            .shadow_xs()
 9133            .when(!has_keybind, |el| {
 9134                let status_colors = cx.theme().status();
 9135
 9136                el.bg(status_colors.error_background)
 9137                    .border_color(status_colors.error.opacity(0.6))
 9138                    .pl_2()
 9139                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9140                    .cursor_default()
 9141                    .hoverable_tooltip(move |_window, cx| {
 9142                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9143                    })
 9144            })
 9145            .children(keybind)
 9146            .child(
 9147                Label::new(label)
 9148                    .size(LabelSize::Small)
 9149                    .when(!has_keybind, |el| {
 9150                        el.color(cx.theme().status().error.into()).strikethrough()
 9151                    }),
 9152            )
 9153            .when(!has_keybind, |el| {
 9154                el.child(
 9155                    h_flex().ml_1().child(
 9156                        Icon::new(IconName::Info)
 9157                            .size(IconSize::Small)
 9158                            .color(cx.theme().status().error.into()),
 9159                    ),
 9160                )
 9161            })
 9162            .when_some(icon, |element, icon| {
 9163                element.child(
 9164                    div()
 9165                        .mt(px(1.5))
 9166                        .child(Icon::new(icon).size(IconSize::Small)),
 9167                )
 9168            })
 9169    }
 9170
 9171    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9172        let accent_color = cx.theme().colors().text_accent;
 9173        let editor_bg_color = cx.theme().colors().editor_background;
 9174        editor_bg_color.blend(accent_color.opacity(0.1))
 9175    }
 9176
 9177    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9178        let accent_color = cx.theme().colors().text_accent;
 9179        let editor_bg_color = cx.theme().colors().editor_background;
 9180        editor_bg_color.blend(accent_color.opacity(0.6))
 9181    }
 9182    fn get_prediction_provider_icon_name(
 9183        provider: &Option<RegisteredEditPredictionProvider>,
 9184    ) -> IconName {
 9185        match provider {
 9186            Some(provider) => match provider.provider.name() {
 9187                "copilot" => IconName::Copilot,
 9188                "supermaven" => IconName::Supermaven,
 9189                _ => IconName::ZedPredict,
 9190            },
 9191            None => IconName::ZedPredict,
 9192        }
 9193    }
 9194
 9195    fn render_edit_prediction_cursor_popover(
 9196        &self,
 9197        min_width: Pixels,
 9198        max_width: Pixels,
 9199        cursor_point: Point,
 9200        style: &EditorStyle,
 9201        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9202        _window: &Window,
 9203        cx: &mut Context<Editor>,
 9204    ) -> Option<AnyElement> {
 9205        let provider = self.edit_prediction_provider.as_ref()?;
 9206        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9207
 9208        let is_refreshing = provider.provider.is_refreshing(cx);
 9209
 9210        fn pending_completion_container(icon: IconName) -> Div {
 9211            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9212        }
 9213
 9214        let completion = match &self.active_edit_prediction {
 9215            Some(prediction) => {
 9216                if !self.has_visible_completions_menu() {
 9217                    const RADIUS: Pixels = px(6.);
 9218                    const BORDER_WIDTH: Pixels = px(1.);
 9219
 9220                    return Some(
 9221                        h_flex()
 9222                            .elevation_2(cx)
 9223                            .border(BORDER_WIDTH)
 9224                            .border_color(cx.theme().colors().border)
 9225                            .when(accept_keystroke.is_none(), |el| {
 9226                                el.border_color(cx.theme().status().error)
 9227                            })
 9228                            .rounded(RADIUS)
 9229                            .rounded_tl(px(0.))
 9230                            .overflow_hidden()
 9231                            .child(div().px_1p5().child(match &prediction.completion {
 9232                                EditPrediction::MoveWithin { target, snapshot } => {
 9233                                    use text::ToPoint as _;
 9234                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9235                                    {
 9236                                        Icon::new(IconName::ZedPredictDown)
 9237                                    } else {
 9238                                        Icon::new(IconName::ZedPredictUp)
 9239                                    }
 9240                                }
 9241                                EditPrediction::MoveOutside { .. } => {
 9242                                    // TODO [zeta2] custom icon for external jump?
 9243                                    Icon::new(provider_icon)
 9244                                }
 9245                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9246                            }))
 9247                            .child(
 9248                                h_flex()
 9249                                    .gap_1()
 9250                                    .py_1()
 9251                                    .px_2()
 9252                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9253                                    .border_l_1()
 9254                                    .border_color(cx.theme().colors().border)
 9255                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9256                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9257                                        el.child(
 9258                                            Label::new("Hold")
 9259                                                .size(LabelSize::Small)
 9260                                                .when(accept_keystroke.is_none(), |el| {
 9261                                                    el.strikethrough()
 9262                                                })
 9263                                                .line_height_style(LineHeightStyle::UiLabel),
 9264                                        )
 9265                                    })
 9266                                    .id("edit_prediction_cursor_popover_keybind")
 9267                                    .when(accept_keystroke.is_none(), |el| {
 9268                                        let status_colors = cx.theme().status();
 9269
 9270                                        el.bg(status_colors.error_background)
 9271                                            .border_color(status_colors.error.opacity(0.6))
 9272                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9273                                            .cursor_default()
 9274                                            .hoverable_tooltip(move |_window, cx| {
 9275                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9276                                                    .into()
 9277                                            })
 9278                                    })
 9279                                    .when_some(
 9280                                        accept_keystroke.as_ref(),
 9281                                        |el, accept_keystroke| {
 9282                                            el.child(h_flex().children(ui::render_modifiers(
 9283                                                accept_keystroke.modifiers(),
 9284                                                PlatformStyle::platform(),
 9285                                                Some(Color::Default),
 9286                                                Some(IconSize::XSmall.rems().into()),
 9287                                                false,
 9288                                            )))
 9289                                        },
 9290                                    ),
 9291                            )
 9292                            .into_any(),
 9293                    );
 9294                }
 9295
 9296                self.render_edit_prediction_cursor_popover_preview(
 9297                    prediction,
 9298                    cursor_point,
 9299                    style,
 9300                    cx,
 9301                )?
 9302            }
 9303
 9304            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9305                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9306                    stale_completion,
 9307                    cursor_point,
 9308                    style,
 9309                    cx,
 9310                )?,
 9311
 9312                None => pending_completion_container(provider_icon)
 9313                    .child(Label::new("...").size(LabelSize::Small)),
 9314            },
 9315
 9316            None => pending_completion_container(provider_icon)
 9317                .child(Label::new("...").size(LabelSize::Small)),
 9318        };
 9319
 9320        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9321            completion
 9322                .with_animation(
 9323                    "loading-completion",
 9324                    Animation::new(Duration::from_secs(2))
 9325                        .repeat()
 9326                        .with_easing(pulsating_between(0.4, 0.8)),
 9327                    |label, delta| label.opacity(delta),
 9328                )
 9329                .into_any_element()
 9330        } else {
 9331            completion.into_any_element()
 9332        };
 9333
 9334        let has_completion = self.active_edit_prediction.is_some();
 9335
 9336        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9337        Some(
 9338            h_flex()
 9339                .min_w(min_width)
 9340                .max_w(max_width)
 9341                .flex_1()
 9342                .elevation_2(cx)
 9343                .border_color(cx.theme().colors().border)
 9344                .child(
 9345                    div()
 9346                        .flex_1()
 9347                        .py_1()
 9348                        .px_2()
 9349                        .overflow_hidden()
 9350                        .child(completion),
 9351                )
 9352                .when_some(accept_keystroke, |el, accept_keystroke| {
 9353                    if !accept_keystroke.modifiers().modified() {
 9354                        return el;
 9355                    }
 9356
 9357                    el.child(
 9358                        h_flex()
 9359                            .h_full()
 9360                            .border_l_1()
 9361                            .rounded_r_lg()
 9362                            .border_color(cx.theme().colors().border)
 9363                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9364                            .gap_1()
 9365                            .py_1()
 9366                            .px_2()
 9367                            .child(
 9368                                h_flex()
 9369                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9370                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9371                                    .child(h_flex().children(ui::render_modifiers(
 9372                                        accept_keystroke.modifiers(),
 9373                                        PlatformStyle::platform(),
 9374                                        Some(if !has_completion {
 9375                                            Color::Muted
 9376                                        } else {
 9377                                            Color::Default
 9378                                        }),
 9379                                        None,
 9380                                        false,
 9381                                    ))),
 9382                            )
 9383                            .child(Label::new("Preview").into_any_element())
 9384                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9385                    )
 9386                })
 9387                .into_any(),
 9388        )
 9389    }
 9390
 9391    fn render_edit_prediction_cursor_popover_preview(
 9392        &self,
 9393        completion: &EditPredictionState,
 9394        cursor_point: Point,
 9395        style: &EditorStyle,
 9396        cx: &mut Context<Editor>,
 9397    ) -> Option<Div> {
 9398        use text::ToPoint as _;
 9399
 9400        fn render_relative_row_jump(
 9401            prefix: impl Into<String>,
 9402            current_row: u32,
 9403            target_row: u32,
 9404        ) -> Div {
 9405            let (row_diff, arrow) = if target_row < current_row {
 9406                (current_row - target_row, IconName::ArrowUp)
 9407            } else {
 9408                (target_row - current_row, IconName::ArrowDown)
 9409            };
 9410
 9411            h_flex()
 9412                .child(
 9413                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9414                        .color(Color::Muted)
 9415                        .size(LabelSize::Small),
 9416                )
 9417                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9418        }
 9419
 9420        let supports_jump = self
 9421            .edit_prediction_provider
 9422            .as_ref()
 9423            .map(|provider| provider.provider.supports_jump_to_edit())
 9424            .unwrap_or(true);
 9425
 9426        match &completion.completion {
 9427            EditPrediction::MoveWithin {
 9428                target, snapshot, ..
 9429            } => {
 9430                if !supports_jump {
 9431                    return None;
 9432                }
 9433
 9434                Some(
 9435                    h_flex()
 9436                        .px_2()
 9437                        .gap_2()
 9438                        .flex_1()
 9439                        .child(
 9440                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9441                                Icon::new(IconName::ZedPredictDown)
 9442                            } else {
 9443                                Icon::new(IconName::ZedPredictUp)
 9444                            },
 9445                        )
 9446                        .child(Label::new("Jump to Edit")),
 9447                )
 9448            }
 9449            EditPrediction::MoveOutside { snapshot, .. } => {
 9450                let file_name = snapshot
 9451                    .file()
 9452                    .map(|file| file.file_name(cx))
 9453                    .unwrap_or("untitled");
 9454                Some(
 9455                    h_flex()
 9456                        .px_2()
 9457                        .gap_2()
 9458                        .flex_1()
 9459                        .child(Icon::new(IconName::ZedPredict))
 9460                        .child(Label::new(format!("Jump to {file_name}"))),
 9461                )
 9462            }
 9463            EditPrediction::Edit {
 9464                edits,
 9465                edit_preview,
 9466                snapshot,
 9467                display_mode: _,
 9468            } => {
 9469                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9470
 9471                let (highlighted_edits, has_more_lines) =
 9472                    if let Some(edit_preview) = edit_preview.as_ref() {
 9473                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9474                            .first_line_preview()
 9475                    } else {
 9476                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9477                    };
 9478
 9479                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9480                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9481
 9482                let preview = h_flex()
 9483                    .gap_1()
 9484                    .min_w_16()
 9485                    .child(styled_text)
 9486                    .when(has_more_lines, |parent| parent.child(""));
 9487
 9488                let left = if supports_jump && first_edit_row != cursor_point.row {
 9489                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9490                        .into_any_element()
 9491                } else {
 9492                    let icon_name =
 9493                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9494                    Icon::new(icon_name).into_any_element()
 9495                };
 9496
 9497                Some(
 9498                    h_flex()
 9499                        .h_full()
 9500                        .flex_1()
 9501                        .gap_2()
 9502                        .pr_1()
 9503                        .overflow_x_hidden()
 9504                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9505                        .child(left)
 9506                        .child(preview),
 9507                )
 9508            }
 9509        }
 9510    }
 9511
 9512    pub fn render_context_menu(
 9513        &self,
 9514        style: &EditorStyle,
 9515        max_height_in_lines: u32,
 9516        window: &mut Window,
 9517        cx: &mut Context<Editor>,
 9518    ) -> Option<AnyElement> {
 9519        let menu = self.context_menu.borrow();
 9520        let menu = menu.as_ref()?;
 9521        if !menu.visible() {
 9522            return None;
 9523        };
 9524        Some(menu.render(style, max_height_in_lines, window, cx))
 9525    }
 9526
 9527    fn render_context_menu_aside(
 9528        &mut self,
 9529        max_size: Size<Pixels>,
 9530        window: &mut Window,
 9531        cx: &mut Context<Editor>,
 9532    ) -> Option<AnyElement> {
 9533        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9534            if menu.visible() {
 9535                menu.render_aside(max_size, window, cx)
 9536            } else {
 9537                None
 9538            }
 9539        })
 9540    }
 9541
 9542    fn hide_context_menu(
 9543        &mut self,
 9544        window: &mut Window,
 9545        cx: &mut Context<Self>,
 9546    ) -> Option<CodeContextMenu> {
 9547        cx.notify();
 9548        self.completion_tasks.clear();
 9549        let context_menu = self.context_menu.borrow_mut().take();
 9550        self.stale_edit_prediction_in_menu.take();
 9551        self.update_visible_edit_prediction(window, cx);
 9552        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9553            && let Some(completion_provider) = &self.completion_provider
 9554        {
 9555            completion_provider.selection_changed(None, window, cx);
 9556        }
 9557        context_menu
 9558    }
 9559
 9560    fn show_snippet_choices(
 9561        &mut self,
 9562        choices: &Vec<String>,
 9563        selection: Range<Anchor>,
 9564        cx: &mut Context<Self>,
 9565    ) {
 9566        let Some((_, buffer, _)) = self
 9567            .buffer()
 9568            .read(cx)
 9569            .excerpt_containing(selection.start, cx)
 9570        else {
 9571            return;
 9572        };
 9573        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9574        else {
 9575            return;
 9576        };
 9577        if buffer != end_buffer {
 9578            log::error!("expected anchor range to have matching buffer IDs");
 9579            return;
 9580        }
 9581
 9582        let id = post_inc(&mut self.next_completion_id);
 9583        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9584        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9585            CompletionsMenu::new_snippet_choices(
 9586                id,
 9587                true,
 9588                choices,
 9589                selection,
 9590                buffer,
 9591                snippet_sort_order,
 9592            ),
 9593        ));
 9594    }
 9595
 9596    pub fn insert_snippet(
 9597        &mut self,
 9598        insertion_ranges: &[Range<usize>],
 9599        snippet: Snippet,
 9600        window: &mut Window,
 9601        cx: &mut Context<Self>,
 9602    ) -> Result<()> {
 9603        struct Tabstop<T> {
 9604            is_end_tabstop: bool,
 9605            ranges: Vec<Range<T>>,
 9606            choices: Option<Vec<String>>,
 9607        }
 9608
 9609        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9610            let snippet_text: Arc<str> = snippet.text.clone().into();
 9611            let edits = insertion_ranges
 9612                .iter()
 9613                .cloned()
 9614                .map(|range| (range, snippet_text.clone()));
 9615            let autoindent_mode = AutoindentMode::Block {
 9616                original_indent_columns: Vec::new(),
 9617            };
 9618            buffer.edit(edits, Some(autoindent_mode), cx);
 9619
 9620            let snapshot = &*buffer.read(cx);
 9621            let snippet = &snippet;
 9622            snippet
 9623                .tabstops
 9624                .iter()
 9625                .map(|tabstop| {
 9626                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9627                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9628                    });
 9629                    let mut tabstop_ranges = tabstop
 9630                        .ranges
 9631                        .iter()
 9632                        .flat_map(|tabstop_range| {
 9633                            let mut delta = 0_isize;
 9634                            insertion_ranges.iter().map(move |insertion_range| {
 9635                                let insertion_start = insertion_range.start as isize + delta;
 9636                                delta +=
 9637                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9638
 9639                                let start = ((insertion_start + tabstop_range.start) as usize)
 9640                                    .min(snapshot.len());
 9641                                let end = ((insertion_start + tabstop_range.end) as usize)
 9642                                    .min(snapshot.len());
 9643                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9644                            })
 9645                        })
 9646                        .collect::<Vec<_>>();
 9647                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9648
 9649                    Tabstop {
 9650                        is_end_tabstop,
 9651                        ranges: tabstop_ranges,
 9652                        choices: tabstop.choices.clone(),
 9653                    }
 9654                })
 9655                .collect::<Vec<_>>()
 9656        });
 9657        if let Some(tabstop) = tabstops.first() {
 9658            self.change_selections(Default::default(), window, cx, |s| {
 9659                // Reverse order so that the first range is the newest created selection.
 9660                // Completions will use it and autoscroll will prioritize it.
 9661                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9662            });
 9663
 9664            if let Some(choices) = &tabstop.choices
 9665                && let Some(selection) = tabstop.ranges.first()
 9666            {
 9667                self.show_snippet_choices(choices, selection.clone(), cx)
 9668            }
 9669
 9670            // If we're already at the last tabstop and it's at the end of the snippet,
 9671            // we're done, we don't need to keep the state around.
 9672            if !tabstop.is_end_tabstop {
 9673                let choices = tabstops
 9674                    .iter()
 9675                    .map(|tabstop| tabstop.choices.clone())
 9676                    .collect();
 9677
 9678                let ranges = tabstops
 9679                    .into_iter()
 9680                    .map(|tabstop| tabstop.ranges)
 9681                    .collect::<Vec<_>>();
 9682
 9683                self.snippet_stack.push(SnippetState {
 9684                    active_index: 0,
 9685                    ranges,
 9686                    choices,
 9687                });
 9688            }
 9689
 9690            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9691            if self.autoclose_regions.is_empty() {
 9692                let snapshot = self.buffer.read(cx).snapshot(cx);
 9693                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9694                    let selection_head = selection.head();
 9695                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9696                        continue;
 9697                    };
 9698
 9699                    let mut bracket_pair = None;
 9700                    let max_lookup_length = scope
 9701                        .brackets()
 9702                        .map(|(pair, _)| {
 9703                            pair.start
 9704                                .as_str()
 9705                                .chars()
 9706                                .count()
 9707                                .max(pair.end.as_str().chars().count())
 9708                        })
 9709                        .max();
 9710                    if let Some(max_lookup_length) = max_lookup_length {
 9711                        let next_text = snapshot
 9712                            .chars_at(selection_head)
 9713                            .take(max_lookup_length)
 9714                            .collect::<String>();
 9715                        let prev_text = snapshot
 9716                            .reversed_chars_at(selection_head)
 9717                            .take(max_lookup_length)
 9718                            .collect::<String>();
 9719
 9720                        for (pair, enabled) in scope.brackets() {
 9721                            if enabled
 9722                                && pair.close
 9723                                && prev_text.starts_with(pair.start.as_str())
 9724                                && next_text.starts_with(pair.end.as_str())
 9725                            {
 9726                                bracket_pair = Some(pair.clone());
 9727                                break;
 9728                            }
 9729                        }
 9730                    }
 9731
 9732                    if let Some(pair) = bracket_pair {
 9733                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9734                        let autoclose_enabled =
 9735                            self.use_autoclose && snapshot_settings.use_autoclose;
 9736                        if autoclose_enabled {
 9737                            let start = snapshot.anchor_after(selection_head);
 9738                            let end = snapshot.anchor_after(selection_head);
 9739                            self.autoclose_regions.push(AutocloseRegion {
 9740                                selection_id: selection.id,
 9741                                range: start..end,
 9742                                pair,
 9743                            });
 9744                        }
 9745                    }
 9746                }
 9747            }
 9748        }
 9749        Ok(())
 9750    }
 9751
 9752    pub fn move_to_next_snippet_tabstop(
 9753        &mut self,
 9754        window: &mut Window,
 9755        cx: &mut Context<Self>,
 9756    ) -> bool {
 9757        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9758    }
 9759
 9760    pub fn move_to_prev_snippet_tabstop(
 9761        &mut self,
 9762        window: &mut Window,
 9763        cx: &mut Context<Self>,
 9764    ) -> bool {
 9765        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9766    }
 9767
 9768    pub fn move_to_snippet_tabstop(
 9769        &mut self,
 9770        bias: Bias,
 9771        window: &mut Window,
 9772        cx: &mut Context<Self>,
 9773    ) -> bool {
 9774        if let Some(mut snippet) = self.snippet_stack.pop() {
 9775            match bias {
 9776                Bias::Left => {
 9777                    if snippet.active_index > 0 {
 9778                        snippet.active_index -= 1;
 9779                    } else {
 9780                        self.snippet_stack.push(snippet);
 9781                        return false;
 9782                    }
 9783                }
 9784                Bias::Right => {
 9785                    if snippet.active_index + 1 < snippet.ranges.len() {
 9786                        snippet.active_index += 1;
 9787                    } else {
 9788                        self.snippet_stack.push(snippet);
 9789                        return false;
 9790                    }
 9791                }
 9792            }
 9793            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9794                self.change_selections(Default::default(), window, cx, |s| {
 9795                    // Reverse order so that the first range is the newest created selection.
 9796                    // Completions will use it and autoscroll will prioritize it.
 9797                    s.select_ranges(current_ranges.iter().rev().cloned())
 9798                });
 9799
 9800                if let Some(choices) = &snippet.choices[snippet.active_index]
 9801                    && let Some(selection) = current_ranges.first()
 9802                {
 9803                    self.show_snippet_choices(choices, selection.clone(), cx);
 9804                }
 9805
 9806                // If snippet state is not at the last tabstop, push it back on the stack
 9807                if snippet.active_index + 1 < snippet.ranges.len() {
 9808                    self.snippet_stack.push(snippet);
 9809                }
 9810                return true;
 9811            }
 9812        }
 9813
 9814        false
 9815    }
 9816
 9817    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9818        self.transact(window, cx, |this, window, cx| {
 9819            this.select_all(&SelectAll, window, cx);
 9820            this.insert("", window, cx);
 9821        });
 9822    }
 9823
 9824    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9825        if self.read_only(cx) {
 9826            return;
 9827        }
 9828        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9829        self.transact(window, cx, |this, window, cx| {
 9830            this.select_autoclose_pair(window, cx);
 9831
 9832            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9833
 9834            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9835            if !this.linked_edit_ranges.is_empty() {
 9836                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9837                let snapshot = this.buffer.read(cx).snapshot(cx);
 9838
 9839                for selection in selections.iter() {
 9840                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9841                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9842                    if selection_start.buffer_id != selection_end.buffer_id {
 9843                        continue;
 9844                    }
 9845                    if let Some(ranges) =
 9846                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9847                    {
 9848                        for (buffer, entries) in ranges {
 9849                            linked_ranges.entry(buffer).or_default().extend(entries);
 9850                        }
 9851                    }
 9852                }
 9853            }
 9854
 9855            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9856            for selection in &mut selections {
 9857                if selection.is_empty() {
 9858                    let old_head = selection.head();
 9859                    let mut new_head =
 9860                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9861                            .to_point(&display_map);
 9862                    if let Some((buffer, line_buffer_range)) = display_map
 9863                        .buffer_snapshot()
 9864                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9865                    {
 9866                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9867                        let indent_len = match indent_size.kind {
 9868                            IndentKind::Space => {
 9869                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9870                            }
 9871                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9872                        };
 9873                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9874                            let indent_len = indent_len.get();
 9875                            new_head = cmp::min(
 9876                                new_head,
 9877                                MultiBufferPoint::new(
 9878                                    old_head.row,
 9879                                    ((old_head.column - 1) / indent_len) * indent_len,
 9880                                ),
 9881                            );
 9882                        }
 9883                    }
 9884
 9885                    selection.set_head(new_head, SelectionGoal::None);
 9886                }
 9887            }
 9888
 9889            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9890            this.insert("", window, cx);
 9891            let empty_str: Arc<str> = Arc::from("");
 9892            for (buffer, edits) in linked_ranges {
 9893                let snapshot = buffer.read(cx).snapshot();
 9894                use text::ToPoint as TP;
 9895
 9896                let edits = edits
 9897                    .into_iter()
 9898                    .map(|range| {
 9899                        let end_point = TP::to_point(&range.end, &snapshot);
 9900                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9901
 9902                        if end_point == start_point {
 9903                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9904                                .saturating_sub(1);
 9905                            start_point =
 9906                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9907                        };
 9908
 9909                        (start_point..end_point, empty_str.clone())
 9910                    })
 9911                    .sorted_by_key(|(range, _)| range.start)
 9912                    .collect::<Vec<_>>();
 9913                buffer.update(cx, |this, cx| {
 9914                    this.edit(edits, None, cx);
 9915                })
 9916            }
 9917            this.refresh_edit_prediction(true, false, window, cx);
 9918            refresh_linked_ranges(this, window, cx);
 9919        });
 9920    }
 9921
 9922    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9923        if self.read_only(cx) {
 9924            return;
 9925        }
 9926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9927        self.transact(window, cx, |this, window, cx| {
 9928            this.change_selections(Default::default(), window, cx, |s| {
 9929                s.move_with(|map, selection| {
 9930                    if selection.is_empty() {
 9931                        let cursor = movement::right(map, selection.head());
 9932                        selection.end = cursor;
 9933                        selection.reversed = true;
 9934                        selection.goal = SelectionGoal::None;
 9935                    }
 9936                })
 9937            });
 9938            this.insert("", window, cx);
 9939            this.refresh_edit_prediction(true, false, window, cx);
 9940        });
 9941    }
 9942
 9943    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9944        if self.mode.is_single_line() {
 9945            cx.propagate();
 9946            return;
 9947        }
 9948
 9949        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9950        if self.move_to_prev_snippet_tabstop(window, cx) {
 9951            return;
 9952        }
 9953        self.outdent(&Outdent, window, cx);
 9954    }
 9955
 9956    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9957        if self.mode.is_single_line() {
 9958            cx.propagate();
 9959            return;
 9960        }
 9961
 9962        if self.move_to_next_snippet_tabstop(window, cx) {
 9963            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9964            return;
 9965        }
 9966        if self.read_only(cx) {
 9967            return;
 9968        }
 9969        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9970        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 9971        let buffer = self.buffer.read(cx);
 9972        let snapshot = buffer.snapshot(cx);
 9973        let rows_iter = selections.iter().map(|s| s.head().row);
 9974        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9975
 9976        let has_some_cursor_in_whitespace = selections
 9977            .iter()
 9978            .filter(|selection| selection.is_empty())
 9979            .any(|selection| {
 9980                let cursor = selection.head();
 9981                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9982                cursor.column < current_indent.len
 9983            });
 9984
 9985        let mut edits = Vec::new();
 9986        let mut prev_edited_row = 0;
 9987        let mut row_delta = 0;
 9988        for selection in &mut selections {
 9989            if selection.start.row != prev_edited_row {
 9990                row_delta = 0;
 9991            }
 9992            prev_edited_row = selection.end.row;
 9993
 9994            // If the selection is non-empty, then increase the indentation of the selected lines.
 9995            if !selection.is_empty() {
 9996                row_delta =
 9997                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9998                continue;
 9999            }
10000
10001            let cursor = selection.head();
10002            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10003            if let Some(suggested_indent) =
10004                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10005            {
10006                // Don't do anything if already at suggested indent
10007                // and there is any other cursor which is not
10008                if has_some_cursor_in_whitespace
10009                    && cursor.column == current_indent.len
10010                    && current_indent.len == suggested_indent.len
10011                {
10012                    continue;
10013                }
10014
10015                // Adjust line and move cursor to suggested indent
10016                // if cursor is not at suggested indent
10017                if cursor.column < suggested_indent.len
10018                    && cursor.column <= current_indent.len
10019                    && current_indent.len <= suggested_indent.len
10020                {
10021                    selection.start = Point::new(cursor.row, suggested_indent.len);
10022                    selection.end = selection.start;
10023                    if row_delta == 0 {
10024                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10025                            cursor.row,
10026                            current_indent,
10027                            suggested_indent,
10028                        ));
10029                        row_delta = suggested_indent.len - current_indent.len;
10030                    }
10031                    continue;
10032                }
10033
10034                // If current indent is more than suggested indent
10035                // only move cursor to current indent and skip indent
10036                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10037                    selection.start = Point::new(cursor.row, current_indent.len);
10038                    selection.end = selection.start;
10039                    continue;
10040                }
10041            }
10042
10043            // Otherwise, insert a hard or soft tab.
10044            let settings = buffer.language_settings_at(cursor, cx);
10045            let tab_size = if settings.hard_tabs {
10046                IndentSize::tab()
10047            } else {
10048                let tab_size = settings.tab_size.get();
10049                let indent_remainder = snapshot
10050                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10051                    .flat_map(str::chars)
10052                    .fold(row_delta % tab_size, |counter: u32, c| {
10053                        if c == '\t' {
10054                            0
10055                        } else {
10056                            (counter + 1) % tab_size
10057                        }
10058                    });
10059
10060                let chars_to_next_tab_stop = tab_size - indent_remainder;
10061                IndentSize::spaces(chars_to_next_tab_stop)
10062            };
10063            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10064            selection.end = selection.start;
10065            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10066            row_delta += tab_size.len;
10067        }
10068
10069        self.transact(window, cx, |this, window, cx| {
10070            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10071            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10072            this.refresh_edit_prediction(true, false, window, cx);
10073        });
10074    }
10075
10076    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10077        if self.read_only(cx) {
10078            return;
10079        }
10080        if self.mode.is_single_line() {
10081            cx.propagate();
10082            return;
10083        }
10084
10085        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10086        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10087        let mut prev_edited_row = 0;
10088        let mut row_delta = 0;
10089        let mut edits = Vec::new();
10090        let buffer = self.buffer.read(cx);
10091        let snapshot = buffer.snapshot(cx);
10092        for selection in &mut selections {
10093            if selection.start.row != prev_edited_row {
10094                row_delta = 0;
10095            }
10096            prev_edited_row = selection.end.row;
10097
10098            row_delta =
10099                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10100        }
10101
10102        self.transact(window, cx, |this, window, cx| {
10103            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10104            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10105        });
10106    }
10107
10108    fn indent_selection(
10109        buffer: &MultiBuffer,
10110        snapshot: &MultiBufferSnapshot,
10111        selection: &mut Selection<Point>,
10112        edits: &mut Vec<(Range<Point>, String)>,
10113        delta_for_start_row: u32,
10114        cx: &App,
10115    ) -> u32 {
10116        let settings = buffer.language_settings_at(selection.start, cx);
10117        let tab_size = settings.tab_size.get();
10118        let indent_kind = if settings.hard_tabs {
10119            IndentKind::Tab
10120        } else {
10121            IndentKind::Space
10122        };
10123        let mut start_row = selection.start.row;
10124        let mut end_row = selection.end.row + 1;
10125
10126        // If a selection ends at the beginning of a line, don't indent
10127        // that last line.
10128        if selection.end.column == 0 && selection.end.row > selection.start.row {
10129            end_row -= 1;
10130        }
10131
10132        // Avoid re-indenting a row that has already been indented by a
10133        // previous selection, but still update this selection's column
10134        // to reflect that indentation.
10135        if delta_for_start_row > 0 {
10136            start_row += 1;
10137            selection.start.column += delta_for_start_row;
10138            if selection.end.row == selection.start.row {
10139                selection.end.column += delta_for_start_row;
10140            }
10141        }
10142
10143        let mut delta_for_end_row = 0;
10144        let has_multiple_rows = start_row + 1 != end_row;
10145        for row in start_row..end_row {
10146            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10147            let indent_delta = match (current_indent.kind, indent_kind) {
10148                (IndentKind::Space, IndentKind::Space) => {
10149                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10150                    IndentSize::spaces(columns_to_next_tab_stop)
10151                }
10152                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10153                (_, IndentKind::Tab) => IndentSize::tab(),
10154            };
10155
10156            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10157                0
10158            } else {
10159                selection.start.column
10160            };
10161            let row_start = Point::new(row, start);
10162            edits.push((
10163                row_start..row_start,
10164                indent_delta.chars().collect::<String>(),
10165            ));
10166
10167            // Update this selection's endpoints to reflect the indentation.
10168            if row == selection.start.row {
10169                selection.start.column += indent_delta.len;
10170            }
10171            if row == selection.end.row {
10172                selection.end.column += indent_delta.len;
10173                delta_for_end_row = indent_delta.len;
10174            }
10175        }
10176
10177        if selection.start.row == selection.end.row {
10178            delta_for_start_row + delta_for_end_row
10179        } else {
10180            delta_for_end_row
10181        }
10182    }
10183
10184    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10185        if self.read_only(cx) {
10186            return;
10187        }
10188        if self.mode.is_single_line() {
10189            cx.propagate();
10190            return;
10191        }
10192
10193        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10194        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10195        let selections = self.selections.all::<Point>(&display_map);
10196        let mut deletion_ranges = Vec::new();
10197        let mut last_outdent = None;
10198        {
10199            let buffer = self.buffer.read(cx);
10200            let snapshot = buffer.snapshot(cx);
10201            for selection in &selections {
10202                let settings = buffer.language_settings_at(selection.start, cx);
10203                let tab_size = settings.tab_size.get();
10204                let mut rows = selection.spanned_rows(false, &display_map);
10205
10206                // Avoid re-outdenting a row that has already been outdented by a
10207                // previous selection.
10208                if let Some(last_row) = last_outdent
10209                    && last_row == rows.start
10210                {
10211                    rows.start = rows.start.next_row();
10212                }
10213                let has_multiple_rows = rows.len() > 1;
10214                for row in rows.iter_rows() {
10215                    let indent_size = snapshot.indent_size_for_line(row);
10216                    if indent_size.len > 0 {
10217                        let deletion_len = match indent_size.kind {
10218                            IndentKind::Space => {
10219                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10220                                if columns_to_prev_tab_stop == 0 {
10221                                    tab_size
10222                                } else {
10223                                    columns_to_prev_tab_stop
10224                                }
10225                            }
10226                            IndentKind::Tab => 1,
10227                        };
10228                        let start = if has_multiple_rows
10229                            || deletion_len > selection.start.column
10230                            || indent_size.len < selection.start.column
10231                        {
10232                            0
10233                        } else {
10234                            selection.start.column - deletion_len
10235                        };
10236                        deletion_ranges.push(
10237                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10238                        );
10239                        last_outdent = Some(row);
10240                    }
10241                }
10242            }
10243        }
10244
10245        self.transact(window, cx, |this, window, cx| {
10246            this.buffer.update(cx, |buffer, cx| {
10247                let empty_str: Arc<str> = Arc::default();
10248                buffer.edit(
10249                    deletion_ranges
10250                        .into_iter()
10251                        .map(|range| (range, empty_str.clone())),
10252                    None,
10253                    cx,
10254                );
10255            });
10256            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10257            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10258        });
10259    }
10260
10261    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10262        if self.read_only(cx) {
10263            return;
10264        }
10265        if self.mode.is_single_line() {
10266            cx.propagate();
10267            return;
10268        }
10269
10270        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10271        let selections = self
10272            .selections
10273            .all::<usize>(&self.display_snapshot(cx))
10274            .into_iter()
10275            .map(|s| s.range());
10276
10277        self.transact(window, cx, |this, window, cx| {
10278            this.buffer.update(cx, |buffer, cx| {
10279                buffer.autoindent_ranges(selections, cx);
10280            });
10281            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10282            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10283        });
10284    }
10285
10286    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10288        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10289        let selections = self.selections.all::<Point>(&display_map);
10290
10291        let mut new_cursors = Vec::new();
10292        let mut edit_ranges = Vec::new();
10293        let mut selections = selections.iter().peekable();
10294        while let Some(selection) = selections.next() {
10295            let mut rows = selection.spanned_rows(false, &display_map);
10296
10297            // Accumulate contiguous regions of rows that we want to delete.
10298            while let Some(next_selection) = selections.peek() {
10299                let next_rows = next_selection.spanned_rows(false, &display_map);
10300                if next_rows.start <= rows.end {
10301                    rows.end = next_rows.end;
10302                    selections.next().unwrap();
10303                } else {
10304                    break;
10305                }
10306            }
10307
10308            let buffer = display_map.buffer_snapshot();
10309            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10310            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10311                // If there's a line after the range, delete the \n from the end of the row range
10312                (
10313                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10314                    rows.end,
10315                )
10316            } else {
10317                // If there isn't a line after the range, delete the \n from the line before the
10318                // start of the row range
10319                edit_start = edit_start.saturating_sub(1);
10320                (buffer.len(), rows.start.previous_row())
10321            };
10322
10323            let text_layout_details = self.text_layout_details(window);
10324            let x = display_map.x_for_display_point(
10325                selection.head().to_display_point(&display_map),
10326                &text_layout_details,
10327            );
10328            let row = Point::new(target_row.0, 0)
10329                .to_display_point(&display_map)
10330                .row();
10331            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10332
10333            new_cursors.push((
10334                selection.id,
10335                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10336                SelectionGoal::None,
10337            ));
10338            edit_ranges.push(edit_start..edit_end);
10339        }
10340
10341        self.transact(window, cx, |this, window, cx| {
10342            let buffer = this.buffer.update(cx, |buffer, cx| {
10343                let empty_str: Arc<str> = Arc::default();
10344                buffer.edit(
10345                    edit_ranges
10346                        .into_iter()
10347                        .map(|range| (range, empty_str.clone())),
10348                    None,
10349                    cx,
10350                );
10351                buffer.snapshot(cx)
10352            });
10353            let new_selections = new_cursors
10354                .into_iter()
10355                .map(|(id, cursor, goal)| {
10356                    let cursor = cursor.to_point(&buffer);
10357                    Selection {
10358                        id,
10359                        start: cursor,
10360                        end: cursor,
10361                        reversed: false,
10362                        goal,
10363                    }
10364                })
10365                .collect();
10366
10367            this.change_selections(Default::default(), window, cx, |s| {
10368                s.select(new_selections);
10369            });
10370        });
10371    }
10372
10373    pub fn join_lines_impl(
10374        &mut self,
10375        insert_whitespace: bool,
10376        window: &mut Window,
10377        cx: &mut Context<Self>,
10378    ) {
10379        if self.read_only(cx) {
10380            return;
10381        }
10382        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10383        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10384            let start = MultiBufferRow(selection.start.row);
10385            // Treat single line selections as if they include the next line. Otherwise this action
10386            // would do nothing for single line selections individual cursors.
10387            let end = if selection.start.row == selection.end.row {
10388                MultiBufferRow(selection.start.row + 1)
10389            } else {
10390                MultiBufferRow(selection.end.row)
10391            };
10392
10393            if let Some(last_row_range) = row_ranges.last_mut()
10394                && start <= last_row_range.end
10395            {
10396                last_row_range.end = end;
10397                continue;
10398            }
10399            row_ranges.push(start..end);
10400        }
10401
10402        let snapshot = self.buffer.read(cx).snapshot(cx);
10403        let mut cursor_positions = Vec::new();
10404        for row_range in &row_ranges {
10405            let anchor = snapshot.anchor_before(Point::new(
10406                row_range.end.previous_row().0,
10407                snapshot.line_len(row_range.end.previous_row()),
10408            ));
10409            cursor_positions.push(anchor..anchor);
10410        }
10411
10412        self.transact(window, cx, |this, window, cx| {
10413            for row_range in row_ranges.into_iter().rev() {
10414                for row in row_range.iter_rows().rev() {
10415                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10416                    let next_line_row = row.next_row();
10417                    let indent = snapshot.indent_size_for_line(next_line_row);
10418                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10419
10420                    let replace =
10421                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10422                            " "
10423                        } else {
10424                            ""
10425                        };
10426
10427                    this.buffer.update(cx, |buffer, cx| {
10428                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10429                    });
10430                }
10431            }
10432
10433            this.change_selections(Default::default(), window, cx, |s| {
10434                s.select_anchor_ranges(cursor_positions)
10435            });
10436        });
10437    }
10438
10439    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10440        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10441        self.join_lines_impl(true, window, cx);
10442    }
10443
10444    pub fn sort_lines_case_sensitive(
10445        &mut self,
10446        _: &SortLinesCaseSensitive,
10447        window: &mut Window,
10448        cx: &mut Context<Self>,
10449    ) {
10450        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10451    }
10452
10453    pub fn sort_lines_by_length(
10454        &mut self,
10455        _: &SortLinesByLength,
10456        window: &mut Window,
10457        cx: &mut Context<Self>,
10458    ) {
10459        self.manipulate_immutable_lines(window, cx, |lines| {
10460            lines.sort_by_key(|&line| line.chars().count())
10461        })
10462    }
10463
10464    pub fn sort_lines_case_insensitive(
10465        &mut self,
10466        _: &SortLinesCaseInsensitive,
10467        window: &mut Window,
10468        cx: &mut Context<Self>,
10469    ) {
10470        self.manipulate_immutable_lines(window, cx, |lines| {
10471            lines.sort_by_key(|line| line.to_lowercase())
10472        })
10473    }
10474
10475    pub fn unique_lines_case_insensitive(
10476        &mut self,
10477        _: &UniqueLinesCaseInsensitive,
10478        window: &mut Window,
10479        cx: &mut Context<Self>,
10480    ) {
10481        self.manipulate_immutable_lines(window, cx, |lines| {
10482            let mut seen = HashSet::default();
10483            lines.retain(|line| seen.insert(line.to_lowercase()));
10484        })
10485    }
10486
10487    pub fn unique_lines_case_sensitive(
10488        &mut self,
10489        _: &UniqueLinesCaseSensitive,
10490        window: &mut Window,
10491        cx: &mut Context<Self>,
10492    ) {
10493        self.manipulate_immutable_lines(window, cx, |lines| {
10494            let mut seen = HashSet::default();
10495            lines.retain(|line| seen.insert(*line));
10496        })
10497    }
10498
10499    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10500        let snapshot = self.buffer.read(cx).snapshot(cx);
10501        for selection in self.selections.disjoint_anchors_arc().iter() {
10502            if snapshot
10503                .language_at(selection.start)
10504                .and_then(|lang| lang.config().wrap_characters.as_ref())
10505                .is_some()
10506            {
10507                return true;
10508            }
10509        }
10510        false
10511    }
10512
10513    fn wrap_selections_in_tag(
10514        &mut self,
10515        _: &WrapSelectionsInTag,
10516        window: &mut Window,
10517        cx: &mut Context<Self>,
10518    ) {
10519        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10520
10521        let snapshot = self.buffer.read(cx).snapshot(cx);
10522
10523        let mut edits = Vec::new();
10524        let mut boundaries = Vec::new();
10525
10526        for selection in self
10527            .selections
10528            .all_adjusted(&self.display_snapshot(cx))
10529            .iter()
10530        {
10531            let Some(wrap_config) = snapshot
10532                .language_at(selection.start)
10533                .and_then(|lang| lang.config().wrap_characters.clone())
10534            else {
10535                continue;
10536            };
10537
10538            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10539            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10540
10541            let start_before = snapshot.anchor_before(selection.start);
10542            let end_after = snapshot.anchor_after(selection.end);
10543
10544            edits.push((start_before..start_before, open_tag));
10545            edits.push((end_after..end_after, close_tag));
10546
10547            boundaries.push((
10548                start_before,
10549                end_after,
10550                wrap_config.start_prefix.len(),
10551                wrap_config.end_suffix.len(),
10552            ));
10553        }
10554
10555        if edits.is_empty() {
10556            return;
10557        }
10558
10559        self.transact(window, cx, |this, window, cx| {
10560            let buffer = this.buffer.update(cx, |buffer, cx| {
10561                buffer.edit(edits, None, cx);
10562                buffer.snapshot(cx)
10563            });
10564
10565            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10566            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10567                boundaries.into_iter()
10568            {
10569                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10570                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10571                new_selections.push(open_offset..open_offset);
10572                new_selections.push(close_offset..close_offset);
10573            }
10574
10575            this.change_selections(Default::default(), window, cx, |s| {
10576                s.select_ranges(new_selections);
10577            });
10578
10579            this.request_autoscroll(Autoscroll::fit(), cx);
10580        });
10581    }
10582
10583    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10584        let Some(project) = self.project.clone() else {
10585            return;
10586        };
10587        self.reload(project, window, cx)
10588            .detach_and_notify_err(window, cx);
10589    }
10590
10591    pub fn restore_file(
10592        &mut self,
10593        _: &::git::RestoreFile,
10594        window: &mut Window,
10595        cx: &mut Context<Self>,
10596    ) {
10597        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10598        let mut buffer_ids = HashSet::default();
10599        let snapshot = self.buffer().read(cx).snapshot(cx);
10600        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10601            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10602        }
10603
10604        let buffer = self.buffer().read(cx);
10605        let ranges = buffer_ids
10606            .into_iter()
10607            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10608            .collect::<Vec<_>>();
10609
10610        self.restore_hunks_in_ranges(ranges, window, cx);
10611    }
10612
10613    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10614        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10615        let selections = self
10616            .selections
10617            .all(&self.display_snapshot(cx))
10618            .into_iter()
10619            .map(|s| s.range())
10620            .collect();
10621        self.restore_hunks_in_ranges(selections, window, cx);
10622    }
10623
10624    pub fn restore_hunks_in_ranges(
10625        &mut self,
10626        ranges: Vec<Range<Point>>,
10627        window: &mut Window,
10628        cx: &mut Context<Editor>,
10629    ) {
10630        let mut revert_changes = HashMap::default();
10631        let chunk_by = self
10632            .snapshot(window, cx)
10633            .hunks_for_ranges(ranges)
10634            .into_iter()
10635            .chunk_by(|hunk| hunk.buffer_id);
10636        for (buffer_id, hunks) in &chunk_by {
10637            let hunks = hunks.collect::<Vec<_>>();
10638            for hunk in &hunks {
10639                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10640            }
10641            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10642        }
10643        drop(chunk_by);
10644        if !revert_changes.is_empty() {
10645            self.transact(window, cx, |editor, window, cx| {
10646                editor.restore(revert_changes, window, cx);
10647            });
10648        }
10649    }
10650
10651    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10652        if let Some(status) = self
10653            .addons
10654            .iter()
10655            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10656        {
10657            return Some(status);
10658        }
10659        self.project
10660            .as_ref()?
10661            .read(cx)
10662            .status_for_buffer_id(buffer_id, cx)
10663    }
10664
10665    pub fn open_active_item_in_terminal(
10666        &mut self,
10667        _: &OpenInTerminal,
10668        window: &mut Window,
10669        cx: &mut Context<Self>,
10670    ) {
10671        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10672            let project_path = buffer.read(cx).project_path(cx)?;
10673            let project = self.project()?.read(cx);
10674            let entry = project.entry_for_path(&project_path, cx)?;
10675            let parent = match &entry.canonical_path {
10676                Some(canonical_path) => canonical_path.to_path_buf(),
10677                None => project.absolute_path(&project_path, cx)?,
10678            }
10679            .parent()?
10680            .to_path_buf();
10681            Some(parent)
10682        }) {
10683            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10684        }
10685    }
10686
10687    fn set_breakpoint_context_menu(
10688        &mut self,
10689        display_row: DisplayRow,
10690        position: Option<Anchor>,
10691        clicked_point: gpui::Point<Pixels>,
10692        window: &mut Window,
10693        cx: &mut Context<Self>,
10694    ) {
10695        let source = self
10696            .buffer
10697            .read(cx)
10698            .snapshot(cx)
10699            .anchor_before(Point::new(display_row.0, 0u32));
10700
10701        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10702
10703        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10704            self,
10705            source,
10706            clicked_point,
10707            context_menu,
10708            window,
10709            cx,
10710        );
10711    }
10712
10713    fn add_edit_breakpoint_block(
10714        &mut self,
10715        anchor: Anchor,
10716        breakpoint: &Breakpoint,
10717        edit_action: BreakpointPromptEditAction,
10718        window: &mut Window,
10719        cx: &mut Context<Self>,
10720    ) {
10721        let weak_editor = cx.weak_entity();
10722        let bp_prompt = cx.new(|cx| {
10723            BreakpointPromptEditor::new(
10724                weak_editor,
10725                anchor,
10726                breakpoint.clone(),
10727                edit_action,
10728                window,
10729                cx,
10730            )
10731        });
10732
10733        let height = bp_prompt.update(cx, |this, cx| {
10734            this.prompt
10735                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10736        });
10737        let cloned_prompt = bp_prompt.clone();
10738        let blocks = vec![BlockProperties {
10739            style: BlockStyle::Sticky,
10740            placement: BlockPlacement::Above(anchor),
10741            height: Some(height),
10742            render: Arc::new(move |cx| {
10743                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10744                cloned_prompt.clone().into_any_element()
10745            }),
10746            priority: 0,
10747        }];
10748
10749        let focus_handle = bp_prompt.focus_handle(cx);
10750        window.focus(&focus_handle);
10751
10752        let block_ids = self.insert_blocks(blocks, None, cx);
10753        bp_prompt.update(cx, |prompt, _| {
10754            prompt.add_block_ids(block_ids);
10755        });
10756    }
10757
10758    pub(crate) fn breakpoint_at_row(
10759        &self,
10760        row: u32,
10761        window: &mut Window,
10762        cx: &mut Context<Self>,
10763    ) -> Option<(Anchor, Breakpoint)> {
10764        let snapshot = self.snapshot(window, cx);
10765        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10766
10767        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10768    }
10769
10770    pub(crate) fn breakpoint_at_anchor(
10771        &self,
10772        breakpoint_position: Anchor,
10773        snapshot: &EditorSnapshot,
10774        cx: &mut Context<Self>,
10775    ) -> Option<(Anchor, Breakpoint)> {
10776        let buffer = self
10777            .buffer
10778            .read(cx)
10779            .buffer_for_anchor(breakpoint_position, cx)?;
10780
10781        let enclosing_excerpt = breakpoint_position.excerpt_id;
10782        let buffer_snapshot = buffer.read(cx).snapshot();
10783
10784        let row = buffer_snapshot
10785            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10786            .row;
10787
10788        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10789        let anchor_end = snapshot
10790            .buffer_snapshot()
10791            .anchor_after(Point::new(row, line_len));
10792
10793        self.breakpoint_store
10794            .as_ref()?
10795            .read_with(cx, |breakpoint_store, cx| {
10796                breakpoint_store
10797                    .breakpoints(
10798                        &buffer,
10799                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10800                        &buffer_snapshot,
10801                        cx,
10802                    )
10803                    .next()
10804                    .and_then(|(bp, _)| {
10805                        let breakpoint_row = buffer_snapshot
10806                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10807                            .row;
10808
10809                        if breakpoint_row == row {
10810                            snapshot
10811                                .buffer_snapshot()
10812                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10813                                .map(|position| (position, bp.bp.clone()))
10814                        } else {
10815                            None
10816                        }
10817                    })
10818            })
10819    }
10820
10821    pub fn edit_log_breakpoint(
10822        &mut self,
10823        _: &EditLogBreakpoint,
10824        window: &mut Window,
10825        cx: &mut Context<Self>,
10826    ) {
10827        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10828            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10829                message: None,
10830                state: BreakpointState::Enabled,
10831                condition: None,
10832                hit_condition: None,
10833            });
10834
10835            self.add_edit_breakpoint_block(
10836                anchor,
10837                &breakpoint,
10838                BreakpointPromptEditAction::Log,
10839                window,
10840                cx,
10841            );
10842        }
10843    }
10844
10845    fn breakpoints_at_cursors(
10846        &self,
10847        window: &mut Window,
10848        cx: &mut Context<Self>,
10849    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10850        let snapshot = self.snapshot(window, cx);
10851        let cursors = self
10852            .selections
10853            .disjoint_anchors_arc()
10854            .iter()
10855            .map(|selection| {
10856                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10857
10858                let breakpoint_position = self
10859                    .breakpoint_at_row(cursor_position.row, window, cx)
10860                    .map(|bp| bp.0)
10861                    .unwrap_or_else(|| {
10862                        snapshot
10863                            .display_snapshot
10864                            .buffer_snapshot()
10865                            .anchor_after(Point::new(cursor_position.row, 0))
10866                    });
10867
10868                let breakpoint = self
10869                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10870                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10871
10872                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10873            })
10874            // 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.
10875            .collect::<HashMap<Anchor, _>>();
10876
10877        cursors.into_iter().collect()
10878    }
10879
10880    pub fn enable_breakpoint(
10881        &mut self,
10882        _: &crate::actions::EnableBreakpoint,
10883        window: &mut Window,
10884        cx: &mut Context<Self>,
10885    ) {
10886        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10887            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10888                continue;
10889            };
10890            self.edit_breakpoint_at_anchor(
10891                anchor,
10892                breakpoint,
10893                BreakpointEditAction::InvertState,
10894                cx,
10895            );
10896        }
10897    }
10898
10899    pub fn disable_breakpoint(
10900        &mut self,
10901        _: &crate::actions::DisableBreakpoint,
10902        window: &mut Window,
10903        cx: &mut Context<Self>,
10904    ) {
10905        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10906            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10907                continue;
10908            };
10909            self.edit_breakpoint_at_anchor(
10910                anchor,
10911                breakpoint,
10912                BreakpointEditAction::InvertState,
10913                cx,
10914            );
10915        }
10916    }
10917
10918    pub fn toggle_breakpoint(
10919        &mut self,
10920        _: &crate::actions::ToggleBreakpoint,
10921        window: &mut Window,
10922        cx: &mut Context<Self>,
10923    ) {
10924        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10925            if let Some(breakpoint) = breakpoint {
10926                self.edit_breakpoint_at_anchor(
10927                    anchor,
10928                    breakpoint,
10929                    BreakpointEditAction::Toggle,
10930                    cx,
10931                );
10932            } else {
10933                self.edit_breakpoint_at_anchor(
10934                    anchor,
10935                    Breakpoint::new_standard(),
10936                    BreakpointEditAction::Toggle,
10937                    cx,
10938                );
10939            }
10940        }
10941    }
10942
10943    pub fn edit_breakpoint_at_anchor(
10944        &mut self,
10945        breakpoint_position: Anchor,
10946        breakpoint: Breakpoint,
10947        edit_action: BreakpointEditAction,
10948        cx: &mut Context<Self>,
10949    ) {
10950        let Some(breakpoint_store) = &self.breakpoint_store else {
10951            return;
10952        };
10953
10954        let Some(buffer) = self
10955            .buffer
10956            .read(cx)
10957            .buffer_for_anchor(breakpoint_position, cx)
10958        else {
10959            return;
10960        };
10961
10962        breakpoint_store.update(cx, |breakpoint_store, cx| {
10963            breakpoint_store.toggle_breakpoint(
10964                buffer,
10965                BreakpointWithPosition {
10966                    position: breakpoint_position.text_anchor,
10967                    bp: breakpoint,
10968                },
10969                edit_action,
10970                cx,
10971            );
10972        });
10973
10974        cx.notify();
10975    }
10976
10977    #[cfg(any(test, feature = "test-support"))]
10978    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10979        self.breakpoint_store.clone()
10980    }
10981
10982    pub fn prepare_restore_change(
10983        &self,
10984        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10985        hunk: &MultiBufferDiffHunk,
10986        cx: &mut App,
10987    ) -> Option<()> {
10988        if hunk.is_created_file() {
10989            return None;
10990        }
10991        let buffer = self.buffer.read(cx);
10992        let diff = buffer.diff_for(hunk.buffer_id)?;
10993        let buffer = buffer.buffer(hunk.buffer_id)?;
10994        let buffer = buffer.read(cx);
10995        let original_text = diff
10996            .read(cx)
10997            .base_text()
10998            .as_rope()
10999            .slice(hunk.diff_base_byte_range.clone());
11000        let buffer_snapshot = buffer.snapshot();
11001        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11002        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11003            probe
11004                .0
11005                .start
11006                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11007                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11008        }) {
11009            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11010            Some(())
11011        } else {
11012            None
11013        }
11014    }
11015
11016    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11017        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11018    }
11019
11020    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11021        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11022    }
11023
11024    fn manipulate_lines<M>(
11025        &mut self,
11026        window: &mut Window,
11027        cx: &mut Context<Self>,
11028        mut manipulate: M,
11029    ) where
11030        M: FnMut(&str) -> LineManipulationResult,
11031    {
11032        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11033
11034        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11035        let buffer = self.buffer.read(cx).snapshot(cx);
11036
11037        let mut edits = Vec::new();
11038
11039        let selections = self.selections.all::<Point>(&display_map);
11040        let mut selections = selections.iter().peekable();
11041        let mut contiguous_row_selections = Vec::new();
11042        let mut new_selections = Vec::new();
11043        let mut added_lines = 0;
11044        let mut removed_lines = 0;
11045
11046        while let Some(selection) = selections.next() {
11047            let (start_row, end_row) = consume_contiguous_rows(
11048                &mut contiguous_row_selections,
11049                selection,
11050                &display_map,
11051                &mut selections,
11052            );
11053
11054            let start_point = Point::new(start_row.0, 0);
11055            let end_point = Point::new(
11056                end_row.previous_row().0,
11057                buffer.line_len(end_row.previous_row()),
11058            );
11059            let text = buffer
11060                .text_for_range(start_point..end_point)
11061                .collect::<String>();
11062
11063            let LineManipulationResult {
11064                new_text,
11065                line_count_before,
11066                line_count_after,
11067            } = manipulate(&text);
11068
11069            edits.push((start_point..end_point, new_text));
11070
11071            // Selections must change based on added and removed line count
11072            let start_row =
11073                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11074            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11075            new_selections.push(Selection {
11076                id: selection.id,
11077                start: start_row,
11078                end: end_row,
11079                goal: SelectionGoal::None,
11080                reversed: selection.reversed,
11081            });
11082
11083            if line_count_after > line_count_before {
11084                added_lines += line_count_after - line_count_before;
11085            } else if line_count_before > line_count_after {
11086                removed_lines += line_count_before - line_count_after;
11087            }
11088        }
11089
11090        self.transact(window, cx, |this, window, cx| {
11091            let buffer = this.buffer.update(cx, |buffer, cx| {
11092                buffer.edit(edits, None, cx);
11093                buffer.snapshot(cx)
11094            });
11095
11096            // Recalculate offsets on newly edited buffer
11097            let new_selections = new_selections
11098                .iter()
11099                .map(|s| {
11100                    let start_point = Point::new(s.start.0, 0);
11101                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11102                    Selection {
11103                        id: s.id,
11104                        start: buffer.point_to_offset(start_point),
11105                        end: buffer.point_to_offset(end_point),
11106                        goal: s.goal,
11107                        reversed: s.reversed,
11108                    }
11109                })
11110                .collect();
11111
11112            this.change_selections(Default::default(), window, cx, |s| {
11113                s.select(new_selections);
11114            });
11115
11116            this.request_autoscroll(Autoscroll::fit(), cx);
11117        });
11118    }
11119
11120    fn manipulate_immutable_lines<Fn>(
11121        &mut self,
11122        window: &mut Window,
11123        cx: &mut Context<Self>,
11124        mut callback: Fn,
11125    ) where
11126        Fn: FnMut(&mut Vec<&str>),
11127    {
11128        self.manipulate_lines(window, cx, |text| {
11129            let mut lines: Vec<&str> = text.split('\n').collect();
11130            let line_count_before = lines.len();
11131
11132            callback(&mut lines);
11133
11134            LineManipulationResult {
11135                new_text: lines.join("\n"),
11136                line_count_before,
11137                line_count_after: lines.len(),
11138            }
11139        });
11140    }
11141
11142    fn manipulate_mutable_lines<Fn>(
11143        &mut self,
11144        window: &mut Window,
11145        cx: &mut Context<Self>,
11146        mut callback: Fn,
11147    ) where
11148        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11149    {
11150        self.manipulate_lines(window, cx, |text| {
11151            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11152            let line_count_before = lines.len();
11153
11154            callback(&mut lines);
11155
11156            LineManipulationResult {
11157                new_text: lines.join("\n"),
11158                line_count_before,
11159                line_count_after: lines.len(),
11160            }
11161        });
11162    }
11163
11164    pub fn convert_indentation_to_spaces(
11165        &mut self,
11166        _: &ConvertIndentationToSpaces,
11167        window: &mut Window,
11168        cx: &mut Context<Self>,
11169    ) {
11170        let settings = self.buffer.read(cx).language_settings(cx);
11171        let tab_size = settings.tab_size.get() as usize;
11172
11173        self.manipulate_mutable_lines(window, cx, |lines| {
11174            // Allocates a reasonably sized scratch buffer once for the whole loop
11175            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11176            // Avoids recomputing spaces that could be inserted many times
11177            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11178                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11179                .collect();
11180
11181            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11182                let mut chars = line.as_ref().chars();
11183                let mut col = 0;
11184                let mut changed = false;
11185
11186                for ch in chars.by_ref() {
11187                    match ch {
11188                        ' ' => {
11189                            reindented_line.push(' ');
11190                            col += 1;
11191                        }
11192                        '\t' => {
11193                            // \t are converted to spaces depending on the current column
11194                            let spaces_len = tab_size - (col % tab_size);
11195                            reindented_line.extend(&space_cache[spaces_len - 1]);
11196                            col += spaces_len;
11197                            changed = true;
11198                        }
11199                        _ => {
11200                            // If we dont append before break, the character is consumed
11201                            reindented_line.push(ch);
11202                            break;
11203                        }
11204                    }
11205                }
11206
11207                if !changed {
11208                    reindented_line.clear();
11209                    continue;
11210                }
11211                // Append the rest of the line and replace old reference with new one
11212                reindented_line.extend(chars);
11213                *line = Cow::Owned(reindented_line.clone());
11214                reindented_line.clear();
11215            }
11216        });
11217    }
11218
11219    pub fn convert_indentation_to_tabs(
11220        &mut self,
11221        _: &ConvertIndentationToTabs,
11222        window: &mut Window,
11223        cx: &mut Context<Self>,
11224    ) {
11225        let settings = self.buffer.read(cx).language_settings(cx);
11226        let tab_size = settings.tab_size.get() as usize;
11227
11228        self.manipulate_mutable_lines(window, cx, |lines| {
11229            // Allocates a reasonably sized buffer once for the whole loop
11230            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11231            // Avoids recomputing spaces that could be inserted many times
11232            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11233                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11234                .collect();
11235
11236            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11237                let mut chars = line.chars();
11238                let mut spaces_count = 0;
11239                let mut first_non_indent_char = None;
11240                let mut changed = false;
11241
11242                for ch in chars.by_ref() {
11243                    match ch {
11244                        ' ' => {
11245                            // Keep track of spaces. Append \t when we reach tab_size
11246                            spaces_count += 1;
11247                            changed = true;
11248                            if spaces_count == tab_size {
11249                                reindented_line.push('\t');
11250                                spaces_count = 0;
11251                            }
11252                        }
11253                        '\t' => {
11254                            reindented_line.push('\t');
11255                            spaces_count = 0;
11256                        }
11257                        _ => {
11258                            // Dont append it yet, we might have remaining spaces
11259                            first_non_indent_char = Some(ch);
11260                            break;
11261                        }
11262                    }
11263                }
11264
11265                if !changed {
11266                    reindented_line.clear();
11267                    continue;
11268                }
11269                // Remaining spaces that didn't make a full tab stop
11270                if spaces_count > 0 {
11271                    reindented_line.extend(&space_cache[spaces_count - 1]);
11272                }
11273                // If we consume an extra character that was not indentation, add it back
11274                if let Some(extra_char) = first_non_indent_char {
11275                    reindented_line.push(extra_char);
11276                }
11277                // Append the rest of the line and replace old reference with new one
11278                reindented_line.extend(chars);
11279                *line = Cow::Owned(reindented_line.clone());
11280                reindented_line.clear();
11281            }
11282        });
11283    }
11284
11285    pub fn convert_to_upper_case(
11286        &mut self,
11287        _: &ConvertToUpperCase,
11288        window: &mut Window,
11289        cx: &mut Context<Self>,
11290    ) {
11291        self.manipulate_text(window, cx, |text| text.to_uppercase())
11292    }
11293
11294    pub fn convert_to_lower_case(
11295        &mut self,
11296        _: &ConvertToLowerCase,
11297        window: &mut Window,
11298        cx: &mut Context<Self>,
11299    ) {
11300        self.manipulate_text(window, cx, |text| text.to_lowercase())
11301    }
11302
11303    pub fn convert_to_title_case(
11304        &mut self,
11305        _: &ConvertToTitleCase,
11306        window: &mut Window,
11307        cx: &mut Context<Self>,
11308    ) {
11309        self.manipulate_text(window, cx, |text| {
11310            text.split('\n')
11311                .map(|line| line.to_case(Case::Title))
11312                .join("\n")
11313        })
11314    }
11315
11316    pub fn convert_to_snake_case(
11317        &mut self,
11318        _: &ConvertToSnakeCase,
11319        window: &mut Window,
11320        cx: &mut Context<Self>,
11321    ) {
11322        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11323    }
11324
11325    pub fn convert_to_kebab_case(
11326        &mut self,
11327        _: &ConvertToKebabCase,
11328        window: &mut Window,
11329        cx: &mut Context<Self>,
11330    ) {
11331        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11332    }
11333
11334    pub fn convert_to_upper_camel_case(
11335        &mut self,
11336        _: &ConvertToUpperCamelCase,
11337        window: &mut Window,
11338        cx: &mut Context<Self>,
11339    ) {
11340        self.manipulate_text(window, cx, |text| {
11341            text.split('\n')
11342                .map(|line| line.to_case(Case::UpperCamel))
11343                .join("\n")
11344        })
11345    }
11346
11347    pub fn convert_to_lower_camel_case(
11348        &mut self,
11349        _: &ConvertToLowerCamelCase,
11350        window: &mut Window,
11351        cx: &mut Context<Self>,
11352    ) {
11353        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11354    }
11355
11356    pub fn convert_to_opposite_case(
11357        &mut self,
11358        _: &ConvertToOppositeCase,
11359        window: &mut Window,
11360        cx: &mut Context<Self>,
11361    ) {
11362        self.manipulate_text(window, cx, |text| {
11363            text.chars()
11364                .fold(String::with_capacity(text.len()), |mut t, c| {
11365                    if c.is_uppercase() {
11366                        t.extend(c.to_lowercase());
11367                    } else {
11368                        t.extend(c.to_uppercase());
11369                    }
11370                    t
11371                })
11372        })
11373    }
11374
11375    pub fn convert_to_sentence_case(
11376        &mut self,
11377        _: &ConvertToSentenceCase,
11378        window: &mut Window,
11379        cx: &mut Context<Self>,
11380    ) {
11381        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11382    }
11383
11384    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11385        self.manipulate_text(window, cx, |text| {
11386            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11387            if has_upper_case_characters {
11388                text.to_lowercase()
11389            } else {
11390                text.to_uppercase()
11391            }
11392        })
11393    }
11394
11395    pub fn convert_to_rot13(
11396        &mut self,
11397        _: &ConvertToRot13,
11398        window: &mut Window,
11399        cx: &mut Context<Self>,
11400    ) {
11401        self.manipulate_text(window, cx, |text| {
11402            text.chars()
11403                .map(|c| match c {
11404                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11405                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11406                    _ => c,
11407                })
11408                .collect()
11409        })
11410    }
11411
11412    pub fn convert_to_rot47(
11413        &mut self,
11414        _: &ConvertToRot47,
11415        window: &mut Window,
11416        cx: &mut Context<Self>,
11417    ) {
11418        self.manipulate_text(window, cx, |text| {
11419            text.chars()
11420                .map(|c| {
11421                    let code_point = c as u32;
11422                    if code_point >= 33 && code_point <= 126 {
11423                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11424                    }
11425                    c
11426                })
11427                .collect()
11428        })
11429    }
11430
11431    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11432    where
11433        Fn: FnMut(&str) -> String,
11434    {
11435        let buffer = self.buffer.read(cx).snapshot(cx);
11436
11437        let mut new_selections = Vec::new();
11438        let mut edits = Vec::new();
11439        let mut selection_adjustment = 0i32;
11440
11441        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11442            let selection_is_empty = selection.is_empty();
11443
11444            let (start, end) = if selection_is_empty {
11445                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11446                (word_range.start, word_range.end)
11447            } else {
11448                (
11449                    buffer.point_to_offset(selection.start),
11450                    buffer.point_to_offset(selection.end),
11451                )
11452            };
11453
11454            let text = buffer.text_for_range(start..end).collect::<String>();
11455            let old_length = text.len() as i32;
11456            let text = callback(&text);
11457
11458            new_selections.push(Selection {
11459                start: (start as i32 - selection_adjustment) as usize,
11460                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11461                goal: SelectionGoal::None,
11462                id: selection.id,
11463                reversed: selection.reversed,
11464            });
11465
11466            selection_adjustment += old_length - text.len() as i32;
11467
11468            edits.push((start..end, text));
11469        }
11470
11471        self.transact(window, cx, |this, window, cx| {
11472            this.buffer.update(cx, |buffer, cx| {
11473                buffer.edit(edits, None, cx);
11474            });
11475
11476            this.change_selections(Default::default(), window, cx, |s| {
11477                s.select(new_selections);
11478            });
11479
11480            this.request_autoscroll(Autoscroll::fit(), cx);
11481        });
11482    }
11483
11484    pub fn move_selection_on_drop(
11485        &mut self,
11486        selection: &Selection<Anchor>,
11487        target: DisplayPoint,
11488        is_cut: bool,
11489        window: &mut Window,
11490        cx: &mut Context<Self>,
11491    ) {
11492        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11493        let buffer = display_map.buffer_snapshot();
11494        let mut edits = Vec::new();
11495        let insert_point = display_map
11496            .clip_point(target, Bias::Left)
11497            .to_point(&display_map);
11498        let text = buffer
11499            .text_for_range(selection.start..selection.end)
11500            .collect::<String>();
11501        if is_cut {
11502            edits.push(((selection.start..selection.end), String::new()));
11503        }
11504        let insert_anchor = buffer.anchor_before(insert_point);
11505        edits.push(((insert_anchor..insert_anchor), text));
11506        let last_edit_start = insert_anchor.bias_left(buffer);
11507        let last_edit_end = insert_anchor.bias_right(buffer);
11508        self.transact(window, cx, |this, window, cx| {
11509            this.buffer.update(cx, |buffer, cx| {
11510                buffer.edit(edits, None, cx);
11511            });
11512            this.change_selections(Default::default(), window, cx, |s| {
11513                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11514            });
11515        });
11516    }
11517
11518    pub fn clear_selection_drag_state(&mut self) {
11519        self.selection_drag_state = SelectionDragState::None;
11520    }
11521
11522    pub fn duplicate(
11523        &mut self,
11524        upwards: bool,
11525        whole_lines: bool,
11526        window: &mut Window,
11527        cx: &mut Context<Self>,
11528    ) {
11529        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11530
11531        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11532        let buffer = display_map.buffer_snapshot();
11533        let selections = self.selections.all::<Point>(&display_map);
11534
11535        let mut edits = Vec::new();
11536        let mut selections_iter = selections.iter().peekable();
11537        while let Some(selection) = selections_iter.next() {
11538            let mut rows = selection.spanned_rows(false, &display_map);
11539            // duplicate line-wise
11540            if whole_lines || selection.start == selection.end {
11541                // Avoid duplicating the same lines twice.
11542                while let Some(next_selection) = selections_iter.peek() {
11543                    let next_rows = next_selection.spanned_rows(false, &display_map);
11544                    if next_rows.start < rows.end {
11545                        rows.end = next_rows.end;
11546                        selections_iter.next().unwrap();
11547                    } else {
11548                        break;
11549                    }
11550                }
11551
11552                // Copy the text from the selected row region and splice it either at the start
11553                // or end of the region.
11554                let start = Point::new(rows.start.0, 0);
11555                let end = Point::new(
11556                    rows.end.previous_row().0,
11557                    buffer.line_len(rows.end.previous_row()),
11558                );
11559
11560                let mut text = buffer.text_for_range(start..end).collect::<String>();
11561
11562                let insert_location = if upwards {
11563                    // When duplicating upward, we need to insert before the current line.
11564                    // If we're on the last line and it doesn't end with a newline,
11565                    // we need to add a newline before the duplicated content.
11566                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11567                        && buffer.max_point().column > 0
11568                        && !text.ends_with('\n');
11569
11570                    if needs_leading_newline {
11571                        text.insert(0, '\n');
11572                        end
11573                    } else {
11574                        text.push('\n');
11575                        Point::new(rows.start.0, 0)
11576                    }
11577                } else {
11578                    text.push('\n');
11579                    start
11580                };
11581                edits.push((insert_location..insert_location, text));
11582            } else {
11583                // duplicate character-wise
11584                let start = selection.start;
11585                let end = selection.end;
11586                let text = buffer.text_for_range(start..end).collect::<String>();
11587                edits.push((selection.end..selection.end, text));
11588            }
11589        }
11590
11591        self.transact(window, cx, |this, window, cx| {
11592            this.buffer.update(cx, |buffer, cx| {
11593                buffer.edit(edits, None, cx);
11594            });
11595
11596            // When duplicating upward with whole lines, move the cursor to the duplicated line
11597            if upwards && whole_lines {
11598                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11599
11600                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11601                    let mut new_ranges = Vec::new();
11602                    let selections = s.all::<Point>(&display_map);
11603                    let mut selections_iter = selections.iter().peekable();
11604
11605                    while let Some(first_selection) = selections_iter.next() {
11606                        // Group contiguous selections together to find the total row span
11607                        let mut group_selections = vec![first_selection];
11608                        let mut rows = first_selection.spanned_rows(false, &display_map);
11609
11610                        while let Some(next_selection) = selections_iter.peek() {
11611                            let next_rows = next_selection.spanned_rows(false, &display_map);
11612                            if next_rows.start < rows.end {
11613                                rows.end = next_rows.end;
11614                                group_selections.push(selections_iter.next().unwrap());
11615                            } else {
11616                                break;
11617                            }
11618                        }
11619
11620                        let row_count = rows.end.0 - rows.start.0;
11621
11622                        // Move all selections in this group up by the total number of duplicated rows
11623                        for selection in group_selections {
11624                            let new_start = Point::new(
11625                                selection.start.row.saturating_sub(row_count),
11626                                selection.start.column,
11627                            );
11628
11629                            let new_end = Point::new(
11630                                selection.end.row.saturating_sub(row_count),
11631                                selection.end.column,
11632                            );
11633
11634                            new_ranges.push(new_start..new_end);
11635                        }
11636                    }
11637
11638                    s.select_ranges(new_ranges);
11639                });
11640            }
11641
11642            this.request_autoscroll(Autoscroll::fit(), cx);
11643        });
11644    }
11645
11646    pub fn duplicate_line_up(
11647        &mut self,
11648        _: &DuplicateLineUp,
11649        window: &mut Window,
11650        cx: &mut Context<Self>,
11651    ) {
11652        self.duplicate(true, true, window, cx);
11653    }
11654
11655    pub fn duplicate_line_down(
11656        &mut self,
11657        _: &DuplicateLineDown,
11658        window: &mut Window,
11659        cx: &mut Context<Self>,
11660    ) {
11661        self.duplicate(false, true, window, cx);
11662    }
11663
11664    pub fn duplicate_selection(
11665        &mut self,
11666        _: &DuplicateSelection,
11667        window: &mut Window,
11668        cx: &mut Context<Self>,
11669    ) {
11670        self.duplicate(false, false, window, cx);
11671    }
11672
11673    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11674        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11675        if self.mode.is_single_line() {
11676            cx.propagate();
11677            return;
11678        }
11679
11680        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11681        let buffer = self.buffer.read(cx).snapshot(cx);
11682
11683        let mut edits = Vec::new();
11684        let mut unfold_ranges = Vec::new();
11685        let mut refold_creases = Vec::new();
11686
11687        let selections = self.selections.all::<Point>(&display_map);
11688        let mut selections = selections.iter().peekable();
11689        let mut contiguous_row_selections = Vec::new();
11690        let mut new_selections = Vec::new();
11691
11692        while let Some(selection) = selections.next() {
11693            // Find all the selections that span a contiguous row range
11694            let (start_row, end_row) = consume_contiguous_rows(
11695                &mut contiguous_row_selections,
11696                selection,
11697                &display_map,
11698                &mut selections,
11699            );
11700
11701            // Move the text spanned by the row range to be before the line preceding the row range
11702            if start_row.0 > 0 {
11703                let range_to_move = Point::new(
11704                    start_row.previous_row().0,
11705                    buffer.line_len(start_row.previous_row()),
11706                )
11707                    ..Point::new(
11708                        end_row.previous_row().0,
11709                        buffer.line_len(end_row.previous_row()),
11710                    );
11711                let insertion_point = display_map
11712                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11713                    .0;
11714
11715                // Don't move lines across excerpts
11716                if buffer
11717                    .excerpt_containing(insertion_point..range_to_move.end)
11718                    .is_some()
11719                {
11720                    let text = buffer
11721                        .text_for_range(range_to_move.clone())
11722                        .flat_map(|s| s.chars())
11723                        .skip(1)
11724                        .chain(['\n'])
11725                        .collect::<String>();
11726
11727                    edits.push((
11728                        buffer.anchor_after(range_to_move.start)
11729                            ..buffer.anchor_before(range_to_move.end),
11730                        String::new(),
11731                    ));
11732                    let insertion_anchor = buffer.anchor_after(insertion_point);
11733                    edits.push((insertion_anchor..insertion_anchor, text));
11734
11735                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11736
11737                    // Move selections up
11738                    new_selections.extend(contiguous_row_selections.drain(..).map(
11739                        |mut selection| {
11740                            selection.start.row -= row_delta;
11741                            selection.end.row -= row_delta;
11742                            selection
11743                        },
11744                    ));
11745
11746                    // Move folds up
11747                    unfold_ranges.push(range_to_move.clone());
11748                    for fold in display_map.folds_in_range(
11749                        buffer.anchor_before(range_to_move.start)
11750                            ..buffer.anchor_after(range_to_move.end),
11751                    ) {
11752                        let mut start = fold.range.start.to_point(&buffer);
11753                        let mut end = fold.range.end.to_point(&buffer);
11754                        start.row -= row_delta;
11755                        end.row -= row_delta;
11756                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11757                    }
11758                }
11759            }
11760
11761            // If we didn't move line(s), preserve the existing selections
11762            new_selections.append(&mut contiguous_row_selections);
11763        }
11764
11765        self.transact(window, cx, |this, window, cx| {
11766            this.unfold_ranges(&unfold_ranges, true, true, cx);
11767            this.buffer.update(cx, |buffer, cx| {
11768                for (range, text) in edits {
11769                    buffer.edit([(range, text)], None, cx);
11770                }
11771            });
11772            this.fold_creases(refold_creases, true, window, cx);
11773            this.change_selections(Default::default(), window, cx, |s| {
11774                s.select(new_selections);
11775            })
11776        });
11777    }
11778
11779    pub fn move_line_down(
11780        &mut self,
11781        _: &MoveLineDown,
11782        window: &mut Window,
11783        cx: &mut Context<Self>,
11784    ) {
11785        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11786        if self.mode.is_single_line() {
11787            cx.propagate();
11788            return;
11789        }
11790
11791        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11792        let buffer = self.buffer.read(cx).snapshot(cx);
11793
11794        let mut edits = Vec::new();
11795        let mut unfold_ranges = Vec::new();
11796        let mut refold_creases = Vec::new();
11797
11798        let selections = self.selections.all::<Point>(&display_map);
11799        let mut selections = selections.iter().peekable();
11800        let mut contiguous_row_selections = Vec::new();
11801        let mut new_selections = Vec::new();
11802
11803        while let Some(selection) = selections.next() {
11804            // Find all the selections that span a contiguous row range
11805            let (start_row, end_row) = consume_contiguous_rows(
11806                &mut contiguous_row_selections,
11807                selection,
11808                &display_map,
11809                &mut selections,
11810            );
11811
11812            // Move the text spanned by the row range to be after the last line of the row range
11813            if end_row.0 <= buffer.max_point().row {
11814                let range_to_move =
11815                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11816                let insertion_point = display_map
11817                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11818                    .0;
11819
11820                // Don't move lines across excerpt boundaries
11821                if buffer
11822                    .excerpt_containing(range_to_move.start..insertion_point)
11823                    .is_some()
11824                {
11825                    let mut text = String::from("\n");
11826                    text.extend(buffer.text_for_range(range_to_move.clone()));
11827                    text.pop(); // Drop trailing newline
11828                    edits.push((
11829                        buffer.anchor_after(range_to_move.start)
11830                            ..buffer.anchor_before(range_to_move.end),
11831                        String::new(),
11832                    ));
11833                    let insertion_anchor = buffer.anchor_after(insertion_point);
11834                    edits.push((insertion_anchor..insertion_anchor, text));
11835
11836                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11837
11838                    // Move selections down
11839                    new_selections.extend(contiguous_row_selections.drain(..).map(
11840                        |mut selection| {
11841                            selection.start.row += row_delta;
11842                            selection.end.row += row_delta;
11843                            selection
11844                        },
11845                    ));
11846
11847                    // Move folds down
11848                    unfold_ranges.push(range_to_move.clone());
11849                    for fold in display_map.folds_in_range(
11850                        buffer.anchor_before(range_to_move.start)
11851                            ..buffer.anchor_after(range_to_move.end),
11852                    ) {
11853                        let mut start = fold.range.start.to_point(&buffer);
11854                        let mut end = fold.range.end.to_point(&buffer);
11855                        start.row += row_delta;
11856                        end.row += row_delta;
11857                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11858                    }
11859                }
11860            }
11861
11862            // If we didn't move line(s), preserve the existing selections
11863            new_selections.append(&mut contiguous_row_selections);
11864        }
11865
11866        self.transact(window, cx, |this, window, cx| {
11867            this.unfold_ranges(&unfold_ranges, true, true, cx);
11868            this.buffer.update(cx, |buffer, cx| {
11869                for (range, text) in edits {
11870                    buffer.edit([(range, text)], None, cx);
11871                }
11872            });
11873            this.fold_creases(refold_creases, true, window, cx);
11874            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11875        });
11876    }
11877
11878    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11879        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11880        let text_layout_details = &self.text_layout_details(window);
11881        self.transact(window, cx, |this, window, cx| {
11882            let edits = this.change_selections(Default::default(), window, cx, |s| {
11883                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11884                s.move_with(|display_map, selection| {
11885                    if !selection.is_empty() {
11886                        return;
11887                    }
11888
11889                    let mut head = selection.head();
11890                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11891                    if head.column() == display_map.line_len(head.row()) {
11892                        transpose_offset = display_map
11893                            .buffer_snapshot()
11894                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11895                    }
11896
11897                    if transpose_offset == 0 {
11898                        return;
11899                    }
11900
11901                    *head.column_mut() += 1;
11902                    head = display_map.clip_point(head, Bias::Right);
11903                    let goal = SelectionGoal::HorizontalPosition(
11904                        display_map
11905                            .x_for_display_point(head, text_layout_details)
11906                            .into(),
11907                    );
11908                    selection.collapse_to(head, goal);
11909
11910                    let transpose_start = display_map
11911                        .buffer_snapshot()
11912                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11913                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11914                        let transpose_end = display_map
11915                            .buffer_snapshot()
11916                            .clip_offset(transpose_offset + 1, Bias::Right);
11917                        if let Some(ch) = display_map
11918                            .buffer_snapshot()
11919                            .chars_at(transpose_start)
11920                            .next()
11921                        {
11922                            edits.push((transpose_start..transpose_offset, String::new()));
11923                            edits.push((transpose_end..transpose_end, ch.to_string()));
11924                        }
11925                    }
11926                });
11927                edits
11928            });
11929            this.buffer
11930                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11931            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
11932            this.change_selections(Default::default(), window, cx, |s| {
11933                s.select(selections);
11934            });
11935        });
11936    }
11937
11938    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11939        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11940        if self.mode.is_single_line() {
11941            cx.propagate();
11942            return;
11943        }
11944
11945        self.rewrap_impl(RewrapOptions::default(), cx)
11946    }
11947
11948    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11949        let buffer = self.buffer.read(cx).snapshot(cx);
11950        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11951
11952        #[derive(Clone, Debug, PartialEq)]
11953        enum CommentFormat {
11954            /// single line comment, with prefix for line
11955            Line(String),
11956            /// single line within a block comment, with prefix for line
11957            BlockLine(String),
11958            /// a single line of a block comment that includes the initial delimiter
11959            BlockCommentWithStart(BlockCommentConfig),
11960            /// a single line of a block comment that includes the ending delimiter
11961            BlockCommentWithEnd(BlockCommentConfig),
11962        }
11963
11964        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11965        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11966            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11967                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11968                .peekable();
11969
11970            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11971                row
11972            } else {
11973                return Vec::new();
11974            };
11975
11976            let language_settings = buffer.language_settings_at(selection.head(), cx);
11977            let language_scope = buffer.language_scope_at(selection.head());
11978
11979            let indent_and_prefix_for_row =
11980                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11981                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11982                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11983                        &language_scope
11984                    {
11985                        let indent_end = Point::new(row, indent.len);
11986                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11987                        let line_text_after_indent = buffer
11988                            .text_for_range(indent_end..line_end)
11989                            .collect::<String>();
11990
11991                        let is_within_comment_override = buffer
11992                            .language_scope_at(indent_end)
11993                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11994                        let comment_delimiters = if is_within_comment_override {
11995                            // we are within a comment syntax node, but we don't
11996                            // yet know what kind of comment: block, doc or line
11997                            match (
11998                                language_scope.documentation_comment(),
11999                                language_scope.block_comment(),
12000                            ) {
12001                                (Some(config), _) | (_, Some(config))
12002                                    if buffer.contains_str_at(indent_end, &config.start) =>
12003                                {
12004                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12005                                }
12006                                (Some(config), _) | (_, Some(config))
12007                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12008                                {
12009                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12010                                }
12011                                (Some(config), _) | (_, Some(config))
12012                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12013                                {
12014                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12015                                }
12016                                (_, _) => language_scope
12017                                    .line_comment_prefixes()
12018                                    .iter()
12019                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12020                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12021                            }
12022                        } else {
12023                            // we not in an overridden comment node, but we may
12024                            // be within a non-overridden line comment node
12025                            language_scope
12026                                .line_comment_prefixes()
12027                                .iter()
12028                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12029                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12030                        };
12031
12032                        let rewrap_prefix = language_scope
12033                            .rewrap_prefixes()
12034                            .iter()
12035                            .find_map(|prefix_regex| {
12036                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12037                                    if mat.start() == 0 {
12038                                        Some(mat.as_str().to_string())
12039                                    } else {
12040                                        None
12041                                    }
12042                                })
12043                            })
12044                            .flatten();
12045                        (comment_delimiters, rewrap_prefix)
12046                    } else {
12047                        (None, None)
12048                    };
12049                    (indent, comment_prefix, rewrap_prefix)
12050                };
12051
12052            let mut ranges = Vec::new();
12053            let from_empty_selection = selection.is_empty();
12054
12055            let mut current_range_start = first_row;
12056            let mut prev_row = first_row;
12057            let (
12058                mut current_range_indent,
12059                mut current_range_comment_delimiters,
12060                mut current_range_rewrap_prefix,
12061            ) = indent_and_prefix_for_row(first_row);
12062
12063            for row in non_blank_rows_iter.skip(1) {
12064                let has_paragraph_break = row > prev_row + 1;
12065
12066                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12067                    indent_and_prefix_for_row(row);
12068
12069                let has_indent_change = row_indent != current_range_indent;
12070                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12071
12072                let has_boundary_change = has_comment_change
12073                    || row_rewrap_prefix.is_some()
12074                    || (has_indent_change && current_range_comment_delimiters.is_some());
12075
12076                if has_paragraph_break || has_boundary_change {
12077                    ranges.push((
12078                        language_settings.clone(),
12079                        Point::new(current_range_start, 0)
12080                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12081                        current_range_indent,
12082                        current_range_comment_delimiters.clone(),
12083                        current_range_rewrap_prefix.clone(),
12084                        from_empty_selection,
12085                    ));
12086                    current_range_start = row;
12087                    current_range_indent = row_indent;
12088                    current_range_comment_delimiters = row_comment_delimiters;
12089                    current_range_rewrap_prefix = row_rewrap_prefix;
12090                }
12091                prev_row = row;
12092            }
12093
12094            ranges.push((
12095                language_settings.clone(),
12096                Point::new(current_range_start, 0)
12097                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12098                current_range_indent,
12099                current_range_comment_delimiters,
12100                current_range_rewrap_prefix,
12101                from_empty_selection,
12102            ));
12103
12104            ranges
12105        });
12106
12107        let mut edits = Vec::new();
12108        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12109
12110        for (
12111            language_settings,
12112            wrap_range,
12113            mut indent_size,
12114            comment_prefix,
12115            rewrap_prefix,
12116            from_empty_selection,
12117        ) in wrap_ranges
12118        {
12119            let mut start_row = wrap_range.start.row;
12120            let mut end_row = wrap_range.end.row;
12121
12122            // Skip selections that overlap with a range that has already been rewrapped.
12123            let selection_range = start_row..end_row;
12124            if rewrapped_row_ranges
12125                .iter()
12126                .any(|range| range.overlaps(&selection_range))
12127            {
12128                continue;
12129            }
12130
12131            let tab_size = language_settings.tab_size;
12132
12133            let (line_prefix, inside_comment) = match &comment_prefix {
12134                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12135                    (Some(prefix.as_str()), true)
12136                }
12137                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12138                    (Some(prefix.as_ref()), true)
12139                }
12140                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12141                    start: _,
12142                    end: _,
12143                    prefix,
12144                    tab_size,
12145                })) => {
12146                    indent_size.len += tab_size;
12147                    (Some(prefix.as_ref()), true)
12148                }
12149                None => (None, false),
12150            };
12151            let indent_prefix = indent_size.chars().collect::<String>();
12152            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12153
12154            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12155                RewrapBehavior::InComments => inside_comment,
12156                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12157                RewrapBehavior::Anywhere => true,
12158            };
12159
12160            let should_rewrap = options.override_language_settings
12161                || allow_rewrap_based_on_language
12162                || self.hard_wrap.is_some();
12163            if !should_rewrap {
12164                continue;
12165            }
12166
12167            if from_empty_selection {
12168                'expand_upwards: while start_row > 0 {
12169                    let prev_row = start_row - 1;
12170                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12171                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12172                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12173                    {
12174                        start_row = prev_row;
12175                    } else {
12176                        break 'expand_upwards;
12177                    }
12178                }
12179
12180                'expand_downwards: while end_row < buffer.max_point().row {
12181                    let next_row = end_row + 1;
12182                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12183                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12184                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12185                    {
12186                        end_row = next_row;
12187                    } else {
12188                        break 'expand_downwards;
12189                    }
12190                }
12191            }
12192
12193            let start = Point::new(start_row, 0);
12194            let start_offset = ToOffset::to_offset(&start, &buffer);
12195            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12196            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12197            let mut first_line_delimiter = None;
12198            let mut last_line_delimiter = None;
12199            let Some(lines_without_prefixes) = selection_text
12200                .lines()
12201                .enumerate()
12202                .map(|(ix, line)| {
12203                    let line_trimmed = line.trim_start();
12204                    if rewrap_prefix.is_some() && ix > 0 {
12205                        Ok(line_trimmed)
12206                    } else if let Some(
12207                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12208                            start,
12209                            prefix,
12210                            end,
12211                            tab_size,
12212                        })
12213                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12214                            start,
12215                            prefix,
12216                            end,
12217                            tab_size,
12218                        }),
12219                    ) = &comment_prefix
12220                    {
12221                        let line_trimmed = line_trimmed
12222                            .strip_prefix(start.as_ref())
12223                            .map(|s| {
12224                                let mut indent_size = indent_size;
12225                                indent_size.len -= tab_size;
12226                                let indent_prefix: String = indent_size.chars().collect();
12227                                first_line_delimiter = Some((indent_prefix, start));
12228                                s.trim_start()
12229                            })
12230                            .unwrap_or(line_trimmed);
12231                        let line_trimmed = line_trimmed
12232                            .strip_suffix(end.as_ref())
12233                            .map(|s| {
12234                                last_line_delimiter = Some(end);
12235                                s.trim_end()
12236                            })
12237                            .unwrap_or(line_trimmed);
12238                        let line_trimmed = line_trimmed
12239                            .strip_prefix(prefix.as_ref())
12240                            .unwrap_or(line_trimmed);
12241                        Ok(line_trimmed)
12242                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12243                        line_trimmed.strip_prefix(prefix).with_context(|| {
12244                            format!("line did not start with prefix {prefix:?}: {line:?}")
12245                        })
12246                    } else {
12247                        line_trimmed
12248                            .strip_prefix(&line_prefix.trim_start())
12249                            .with_context(|| {
12250                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12251                            })
12252                    }
12253                })
12254                .collect::<Result<Vec<_>, _>>()
12255                .log_err()
12256            else {
12257                continue;
12258            };
12259
12260            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12261                buffer
12262                    .language_settings_at(Point::new(start_row, 0), cx)
12263                    .preferred_line_length as usize
12264            });
12265
12266            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12267                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12268            } else {
12269                line_prefix.clone()
12270            };
12271
12272            let wrapped_text = {
12273                let mut wrapped_text = wrap_with_prefix(
12274                    line_prefix,
12275                    subsequent_lines_prefix,
12276                    lines_without_prefixes.join("\n"),
12277                    wrap_column,
12278                    tab_size,
12279                    options.preserve_existing_whitespace,
12280                );
12281
12282                if let Some((indent, delimiter)) = first_line_delimiter {
12283                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12284                }
12285                if let Some(last_line) = last_line_delimiter {
12286                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12287                }
12288
12289                wrapped_text
12290            };
12291
12292            // TODO: should always use char-based diff while still supporting cursor behavior that
12293            // matches vim.
12294            let mut diff_options = DiffOptions::default();
12295            if options.override_language_settings {
12296                diff_options.max_word_diff_len = 0;
12297                diff_options.max_word_diff_line_count = 0;
12298            } else {
12299                diff_options.max_word_diff_len = usize::MAX;
12300                diff_options.max_word_diff_line_count = usize::MAX;
12301            }
12302
12303            for (old_range, new_text) in
12304                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12305            {
12306                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12307                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12308                edits.push((edit_start..edit_end, new_text));
12309            }
12310
12311            rewrapped_row_ranges.push(start_row..=end_row);
12312        }
12313
12314        self.buffer
12315            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12316    }
12317
12318    pub fn cut_common(
12319        &mut self,
12320        cut_no_selection_line: bool,
12321        window: &mut Window,
12322        cx: &mut Context<Self>,
12323    ) -> ClipboardItem {
12324        let mut text = String::new();
12325        let buffer = self.buffer.read(cx).snapshot(cx);
12326        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12327        let mut clipboard_selections = Vec::with_capacity(selections.len());
12328        {
12329            let max_point = buffer.max_point();
12330            let mut is_first = true;
12331            for selection in &mut selections {
12332                let is_entire_line =
12333                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12334                if is_entire_line {
12335                    selection.start = Point::new(selection.start.row, 0);
12336                    if !selection.is_empty() && selection.end.column == 0 {
12337                        selection.end = cmp::min(max_point, selection.end);
12338                    } else {
12339                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12340                    }
12341                    selection.goal = SelectionGoal::None;
12342                }
12343                if is_first {
12344                    is_first = false;
12345                } else {
12346                    text += "\n";
12347                }
12348                let mut len = 0;
12349                for chunk in buffer.text_for_range(selection.start..selection.end) {
12350                    text.push_str(chunk);
12351                    len += chunk.len();
12352                }
12353                clipboard_selections.push(ClipboardSelection {
12354                    len,
12355                    is_entire_line,
12356                    first_line_indent: buffer
12357                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12358                        .len,
12359                });
12360            }
12361        }
12362
12363        self.transact(window, cx, |this, window, cx| {
12364            this.change_selections(Default::default(), window, cx, |s| {
12365                s.select(selections);
12366            });
12367            this.insert("", window, cx);
12368        });
12369        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12370    }
12371
12372    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12373        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12374        let item = self.cut_common(true, window, cx);
12375        cx.write_to_clipboard(item);
12376    }
12377
12378    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12379        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12380        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12381            s.move_with(|snapshot, sel| {
12382                if sel.is_empty() {
12383                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12384                }
12385                if sel.is_empty() {
12386                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12387                }
12388            });
12389        });
12390        let item = self.cut_common(false, window, cx);
12391        cx.set_global(KillRing(item))
12392    }
12393
12394    pub fn kill_ring_yank(
12395        &mut self,
12396        _: &KillRingYank,
12397        window: &mut Window,
12398        cx: &mut Context<Self>,
12399    ) {
12400        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12401        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12402            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12403                (kill_ring.text().to_string(), kill_ring.metadata_json())
12404            } else {
12405                return;
12406            }
12407        } else {
12408            return;
12409        };
12410        self.do_paste(&text, metadata, false, window, cx);
12411    }
12412
12413    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12414        self.do_copy(true, cx);
12415    }
12416
12417    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12418        self.do_copy(false, cx);
12419    }
12420
12421    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12422        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12423        let buffer = self.buffer.read(cx).read(cx);
12424        let mut text = String::new();
12425
12426        let mut clipboard_selections = Vec::with_capacity(selections.len());
12427        {
12428            let max_point = buffer.max_point();
12429            let mut is_first = true;
12430            for selection in &selections {
12431                let mut start = selection.start;
12432                let mut end = selection.end;
12433                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12434                let mut add_trailing_newline = false;
12435                if is_entire_line {
12436                    start = Point::new(start.row, 0);
12437                    let next_line_start = Point::new(end.row + 1, 0);
12438                    if next_line_start <= max_point {
12439                        end = next_line_start;
12440                    } else {
12441                        // We're on the last line without a trailing newline.
12442                        // Copy to the end of the line and add a newline afterwards.
12443                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12444                        add_trailing_newline = true;
12445                    }
12446                }
12447
12448                let mut trimmed_selections = Vec::new();
12449                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12450                    let row = MultiBufferRow(start.row);
12451                    let first_indent = buffer.indent_size_for_line(row);
12452                    if first_indent.len == 0 || start.column > first_indent.len {
12453                        trimmed_selections.push(start..end);
12454                    } else {
12455                        trimmed_selections.push(
12456                            Point::new(row.0, first_indent.len)
12457                                ..Point::new(row.0, buffer.line_len(row)),
12458                        );
12459                        for row in start.row + 1..=end.row {
12460                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12461                            if row == end.row {
12462                                line_len = end.column;
12463                            }
12464                            if line_len == 0 {
12465                                trimmed_selections
12466                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12467                                continue;
12468                            }
12469                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12470                            if row_indent_size.len >= first_indent.len {
12471                                trimmed_selections.push(
12472                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12473                                );
12474                            } else {
12475                                trimmed_selections.clear();
12476                                trimmed_selections.push(start..end);
12477                                break;
12478                            }
12479                        }
12480                    }
12481                } else {
12482                    trimmed_selections.push(start..end);
12483                }
12484
12485                for trimmed_range in trimmed_selections {
12486                    if is_first {
12487                        is_first = false;
12488                    } else {
12489                        text += "\n";
12490                    }
12491                    let mut len = 0;
12492                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12493                        text.push_str(chunk);
12494                        len += chunk.len();
12495                    }
12496                    if add_trailing_newline {
12497                        text.push('\n');
12498                        len += 1;
12499                    }
12500                    clipboard_selections.push(ClipboardSelection {
12501                        len,
12502                        is_entire_line,
12503                        first_line_indent: buffer
12504                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12505                            .len,
12506                    });
12507                }
12508            }
12509        }
12510
12511        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12512            text,
12513            clipboard_selections,
12514        ));
12515    }
12516
12517    pub fn do_paste(
12518        &mut self,
12519        text: &String,
12520        clipboard_selections: Option<Vec<ClipboardSelection>>,
12521        handle_entire_lines: bool,
12522        window: &mut Window,
12523        cx: &mut Context<Self>,
12524    ) {
12525        if self.read_only(cx) {
12526            return;
12527        }
12528
12529        let clipboard_text = Cow::Borrowed(text.as_str());
12530
12531        self.transact(window, cx, |this, window, cx| {
12532            let had_active_edit_prediction = this.has_active_edit_prediction();
12533            let display_map = this.display_snapshot(cx);
12534            let old_selections = this.selections.all::<usize>(&display_map);
12535            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12536
12537            if let Some(mut clipboard_selections) = clipboard_selections {
12538                let all_selections_were_entire_line =
12539                    clipboard_selections.iter().all(|s| s.is_entire_line);
12540                let first_selection_indent_column =
12541                    clipboard_selections.first().map(|s| s.first_line_indent);
12542                if clipboard_selections.len() != old_selections.len() {
12543                    clipboard_selections.drain(..);
12544                }
12545                let mut auto_indent_on_paste = true;
12546
12547                this.buffer.update(cx, |buffer, cx| {
12548                    let snapshot = buffer.read(cx);
12549                    auto_indent_on_paste = snapshot
12550                        .language_settings_at(cursor_offset, cx)
12551                        .auto_indent_on_paste;
12552
12553                    let mut start_offset = 0;
12554                    let mut edits = Vec::new();
12555                    let mut original_indent_columns = Vec::new();
12556                    for (ix, selection) in old_selections.iter().enumerate() {
12557                        let to_insert;
12558                        let entire_line;
12559                        let original_indent_column;
12560                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12561                            let end_offset = start_offset + clipboard_selection.len;
12562                            to_insert = &clipboard_text[start_offset..end_offset];
12563                            entire_line = clipboard_selection.is_entire_line;
12564                            start_offset = end_offset + 1;
12565                            original_indent_column = Some(clipboard_selection.first_line_indent);
12566                        } else {
12567                            to_insert = &*clipboard_text;
12568                            entire_line = all_selections_were_entire_line;
12569                            original_indent_column = first_selection_indent_column
12570                        }
12571
12572                        let (range, to_insert) =
12573                            if selection.is_empty() && handle_entire_lines && entire_line {
12574                                // If the corresponding selection was empty when this slice of the
12575                                // clipboard text was written, then the entire line containing the
12576                                // selection was copied. If this selection is also currently empty,
12577                                // then paste the line before the current line of the buffer.
12578                                let column = selection.start.to_point(&snapshot).column as usize;
12579                                let line_start = selection.start - column;
12580                                (line_start..line_start, Cow::Borrowed(to_insert))
12581                            } else {
12582                                let language = snapshot.language_at(selection.head());
12583                                let range = selection.range();
12584                                if let Some(language) = language
12585                                    && language.name() == "Markdown".into()
12586                                {
12587                                    edit_for_markdown_paste(
12588                                        &snapshot,
12589                                        range,
12590                                        to_insert,
12591                                        url::Url::parse(to_insert).ok(),
12592                                    )
12593                                } else {
12594                                    (range, Cow::Borrowed(to_insert))
12595                                }
12596                            };
12597
12598                        edits.push((range, to_insert));
12599                        original_indent_columns.push(original_indent_column);
12600                    }
12601                    drop(snapshot);
12602
12603                    buffer.edit(
12604                        edits,
12605                        if auto_indent_on_paste {
12606                            Some(AutoindentMode::Block {
12607                                original_indent_columns,
12608                            })
12609                        } else {
12610                            None
12611                        },
12612                        cx,
12613                    );
12614                });
12615
12616                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12617                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12618            } else {
12619                let url = url::Url::parse(&clipboard_text).ok();
12620
12621                let auto_indent_mode = if !clipboard_text.is_empty() {
12622                    Some(AutoindentMode::Block {
12623                        original_indent_columns: Vec::new(),
12624                    })
12625                } else {
12626                    None
12627                };
12628
12629                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12630                    let snapshot = buffer.snapshot(cx);
12631
12632                    let anchors = old_selections
12633                        .iter()
12634                        .map(|s| {
12635                            let anchor = snapshot.anchor_after(s.head());
12636                            s.map(|_| anchor)
12637                        })
12638                        .collect::<Vec<_>>();
12639
12640                    let mut edits = Vec::new();
12641
12642                    for selection in old_selections.iter() {
12643                        let language = snapshot.language_at(selection.head());
12644                        let range = selection.range();
12645
12646                        let (edit_range, edit_text) = if let Some(language) = language
12647                            && language.name() == "Markdown".into()
12648                        {
12649                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12650                        } else {
12651                            (range, clipboard_text.clone())
12652                        };
12653
12654                        edits.push((edit_range, edit_text));
12655                    }
12656
12657                    drop(snapshot);
12658                    buffer.edit(edits, auto_indent_mode, cx);
12659
12660                    anchors
12661                });
12662
12663                this.change_selections(Default::default(), window, cx, |s| {
12664                    s.select_anchors(selection_anchors);
12665                });
12666            }
12667
12668            let trigger_in_words =
12669                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12670
12671            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12672        });
12673    }
12674
12675    pub fn diff_clipboard_with_selection(
12676        &mut self,
12677        _: &DiffClipboardWithSelection,
12678        window: &mut Window,
12679        cx: &mut Context<Self>,
12680    ) {
12681        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12682
12683        if selections.is_empty() {
12684            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12685            return;
12686        };
12687
12688        let clipboard_text = match cx.read_from_clipboard() {
12689            Some(item) => match item.entries().first() {
12690                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12691                _ => None,
12692            },
12693            None => None,
12694        };
12695
12696        let Some(clipboard_text) = clipboard_text else {
12697            log::warn!("Clipboard doesn't contain text.");
12698            return;
12699        };
12700
12701        window.dispatch_action(
12702            Box::new(DiffClipboardWithSelectionData {
12703                clipboard_text,
12704                editor: cx.entity(),
12705            }),
12706            cx,
12707        );
12708    }
12709
12710    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12711        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12712        if let Some(item) = cx.read_from_clipboard() {
12713            let entries = item.entries();
12714
12715            match entries.first() {
12716                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12717                // of all the pasted entries.
12718                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12719                    .do_paste(
12720                        clipboard_string.text(),
12721                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12722                        true,
12723                        window,
12724                        cx,
12725                    ),
12726                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12727            }
12728        }
12729    }
12730
12731    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12732        if self.read_only(cx) {
12733            return;
12734        }
12735
12736        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12737
12738        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12739            if let Some((selections, _)) =
12740                self.selection_history.transaction(transaction_id).cloned()
12741            {
12742                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12743                    s.select_anchors(selections.to_vec());
12744                });
12745            } else {
12746                log::error!(
12747                    "No entry in selection_history found for undo. \
12748                     This may correspond to a bug where undo does not update the selection. \
12749                     If this is occurring, please add details to \
12750                     https://github.com/zed-industries/zed/issues/22692"
12751                );
12752            }
12753            self.request_autoscroll(Autoscroll::fit(), cx);
12754            self.unmark_text(window, cx);
12755            self.refresh_edit_prediction(true, false, window, cx);
12756            cx.emit(EditorEvent::Edited { transaction_id });
12757            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12758        }
12759    }
12760
12761    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12762        if self.read_only(cx) {
12763            return;
12764        }
12765
12766        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12767
12768        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12769            if let Some((_, Some(selections))) =
12770                self.selection_history.transaction(transaction_id).cloned()
12771            {
12772                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12773                    s.select_anchors(selections.to_vec());
12774                });
12775            } else {
12776                log::error!(
12777                    "No entry in selection_history found for redo. \
12778                     This may correspond to a bug where undo does not update the selection. \
12779                     If this is occurring, please add details to \
12780                     https://github.com/zed-industries/zed/issues/22692"
12781                );
12782            }
12783            self.request_autoscroll(Autoscroll::fit(), cx);
12784            self.unmark_text(window, cx);
12785            self.refresh_edit_prediction(true, false, window, cx);
12786            cx.emit(EditorEvent::Edited { transaction_id });
12787        }
12788    }
12789
12790    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12791        self.buffer
12792            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12793    }
12794
12795    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12796        self.buffer
12797            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12798    }
12799
12800    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12801        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12802        self.change_selections(Default::default(), window, cx, |s| {
12803            s.move_with(|map, selection| {
12804                let cursor = if selection.is_empty() {
12805                    movement::left(map, selection.start)
12806                } else {
12807                    selection.start
12808                };
12809                selection.collapse_to(cursor, SelectionGoal::None);
12810            });
12811        })
12812    }
12813
12814    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12815        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12816        self.change_selections(Default::default(), window, cx, |s| {
12817            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12818        })
12819    }
12820
12821    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12822        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12823        self.change_selections(Default::default(), window, cx, |s| {
12824            s.move_with(|map, selection| {
12825                let cursor = if selection.is_empty() {
12826                    movement::right(map, selection.end)
12827                } else {
12828                    selection.end
12829                };
12830                selection.collapse_to(cursor, SelectionGoal::None)
12831            });
12832        })
12833    }
12834
12835    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12836        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12837        self.change_selections(Default::default(), window, cx, |s| {
12838            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12839        });
12840    }
12841
12842    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12843        if self.take_rename(true, window, cx).is_some() {
12844            return;
12845        }
12846
12847        if self.mode.is_single_line() {
12848            cx.propagate();
12849            return;
12850        }
12851
12852        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12853
12854        let text_layout_details = &self.text_layout_details(window);
12855        let selection_count = self.selections.count();
12856        let first_selection = self.selections.first_anchor();
12857
12858        self.change_selections(Default::default(), window, cx, |s| {
12859            s.move_with(|map, selection| {
12860                if !selection.is_empty() {
12861                    selection.goal = SelectionGoal::None;
12862                }
12863                let (cursor, goal) = movement::up(
12864                    map,
12865                    selection.start,
12866                    selection.goal,
12867                    false,
12868                    text_layout_details,
12869                );
12870                selection.collapse_to(cursor, goal);
12871            });
12872        });
12873
12874        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12875        {
12876            cx.propagate();
12877        }
12878    }
12879
12880    pub fn move_up_by_lines(
12881        &mut self,
12882        action: &MoveUpByLines,
12883        window: &mut Window,
12884        cx: &mut Context<Self>,
12885    ) {
12886        if self.take_rename(true, window, cx).is_some() {
12887            return;
12888        }
12889
12890        if self.mode.is_single_line() {
12891            cx.propagate();
12892            return;
12893        }
12894
12895        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12896
12897        let text_layout_details = &self.text_layout_details(window);
12898
12899        self.change_selections(Default::default(), window, cx, |s| {
12900            s.move_with(|map, selection| {
12901                if !selection.is_empty() {
12902                    selection.goal = SelectionGoal::None;
12903                }
12904                let (cursor, goal) = movement::up_by_rows(
12905                    map,
12906                    selection.start,
12907                    action.lines,
12908                    selection.goal,
12909                    false,
12910                    text_layout_details,
12911                );
12912                selection.collapse_to(cursor, goal);
12913            });
12914        })
12915    }
12916
12917    pub fn move_down_by_lines(
12918        &mut self,
12919        action: &MoveDownByLines,
12920        window: &mut Window,
12921        cx: &mut Context<Self>,
12922    ) {
12923        if self.take_rename(true, window, cx).is_some() {
12924            return;
12925        }
12926
12927        if self.mode.is_single_line() {
12928            cx.propagate();
12929            return;
12930        }
12931
12932        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12933
12934        let text_layout_details = &self.text_layout_details(window);
12935
12936        self.change_selections(Default::default(), window, cx, |s| {
12937            s.move_with(|map, selection| {
12938                if !selection.is_empty() {
12939                    selection.goal = SelectionGoal::None;
12940                }
12941                let (cursor, goal) = movement::down_by_rows(
12942                    map,
12943                    selection.start,
12944                    action.lines,
12945                    selection.goal,
12946                    false,
12947                    text_layout_details,
12948                );
12949                selection.collapse_to(cursor, goal);
12950            });
12951        })
12952    }
12953
12954    pub fn select_down_by_lines(
12955        &mut self,
12956        action: &SelectDownByLines,
12957        window: &mut Window,
12958        cx: &mut Context<Self>,
12959    ) {
12960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12961        let text_layout_details = &self.text_layout_details(window);
12962        self.change_selections(Default::default(), window, cx, |s| {
12963            s.move_heads_with(|map, head, goal| {
12964                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12965            })
12966        })
12967    }
12968
12969    pub fn select_up_by_lines(
12970        &mut self,
12971        action: &SelectUpByLines,
12972        window: &mut Window,
12973        cx: &mut Context<Self>,
12974    ) {
12975        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12976        let text_layout_details = &self.text_layout_details(window);
12977        self.change_selections(Default::default(), window, cx, |s| {
12978            s.move_heads_with(|map, head, goal| {
12979                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12980            })
12981        })
12982    }
12983
12984    pub fn select_page_up(
12985        &mut self,
12986        _: &SelectPageUp,
12987        window: &mut Window,
12988        cx: &mut Context<Self>,
12989    ) {
12990        let Some(row_count) = self.visible_row_count() else {
12991            return;
12992        };
12993
12994        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12995
12996        let text_layout_details = &self.text_layout_details(window);
12997
12998        self.change_selections(Default::default(), window, cx, |s| {
12999            s.move_heads_with(|map, head, goal| {
13000                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13001            })
13002        })
13003    }
13004
13005    pub fn move_page_up(
13006        &mut self,
13007        action: &MovePageUp,
13008        window: &mut Window,
13009        cx: &mut Context<Self>,
13010    ) {
13011        if self.take_rename(true, window, cx).is_some() {
13012            return;
13013        }
13014
13015        if self
13016            .context_menu
13017            .borrow_mut()
13018            .as_mut()
13019            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13020            .unwrap_or(false)
13021        {
13022            return;
13023        }
13024
13025        if matches!(self.mode, EditorMode::SingleLine) {
13026            cx.propagate();
13027            return;
13028        }
13029
13030        let Some(row_count) = self.visible_row_count() else {
13031            return;
13032        };
13033
13034        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13035
13036        let effects = if action.center_cursor {
13037            SelectionEffects::scroll(Autoscroll::center())
13038        } else {
13039            SelectionEffects::default()
13040        };
13041
13042        let text_layout_details = &self.text_layout_details(window);
13043
13044        self.change_selections(effects, window, cx, |s| {
13045            s.move_with(|map, selection| {
13046                if !selection.is_empty() {
13047                    selection.goal = SelectionGoal::None;
13048                }
13049                let (cursor, goal) = movement::up_by_rows(
13050                    map,
13051                    selection.end,
13052                    row_count,
13053                    selection.goal,
13054                    false,
13055                    text_layout_details,
13056                );
13057                selection.collapse_to(cursor, goal);
13058            });
13059        });
13060    }
13061
13062    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13063        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13064        let text_layout_details = &self.text_layout_details(window);
13065        self.change_selections(Default::default(), window, cx, |s| {
13066            s.move_heads_with(|map, head, goal| {
13067                movement::up(map, head, goal, false, text_layout_details)
13068            })
13069        })
13070    }
13071
13072    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13073        self.take_rename(true, window, cx);
13074
13075        if self.mode.is_single_line() {
13076            cx.propagate();
13077            return;
13078        }
13079
13080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13081
13082        let text_layout_details = &self.text_layout_details(window);
13083        let selection_count = self.selections.count();
13084        let first_selection = self.selections.first_anchor();
13085
13086        self.change_selections(Default::default(), window, cx, |s| {
13087            s.move_with(|map, selection| {
13088                if !selection.is_empty() {
13089                    selection.goal = SelectionGoal::None;
13090                }
13091                let (cursor, goal) = movement::down(
13092                    map,
13093                    selection.end,
13094                    selection.goal,
13095                    false,
13096                    text_layout_details,
13097                );
13098                selection.collapse_to(cursor, goal);
13099            });
13100        });
13101
13102        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13103        {
13104            cx.propagate();
13105        }
13106    }
13107
13108    pub fn select_page_down(
13109        &mut self,
13110        _: &SelectPageDown,
13111        window: &mut Window,
13112        cx: &mut Context<Self>,
13113    ) {
13114        let Some(row_count) = self.visible_row_count() else {
13115            return;
13116        };
13117
13118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13119
13120        let text_layout_details = &self.text_layout_details(window);
13121
13122        self.change_selections(Default::default(), window, cx, |s| {
13123            s.move_heads_with(|map, head, goal| {
13124                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13125            })
13126        })
13127    }
13128
13129    pub fn move_page_down(
13130        &mut self,
13131        action: &MovePageDown,
13132        window: &mut Window,
13133        cx: &mut Context<Self>,
13134    ) {
13135        if self.take_rename(true, window, cx).is_some() {
13136            return;
13137        }
13138
13139        if self
13140            .context_menu
13141            .borrow_mut()
13142            .as_mut()
13143            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13144            .unwrap_or(false)
13145        {
13146            return;
13147        }
13148
13149        if matches!(self.mode, EditorMode::SingleLine) {
13150            cx.propagate();
13151            return;
13152        }
13153
13154        let Some(row_count) = self.visible_row_count() else {
13155            return;
13156        };
13157
13158        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13159
13160        let effects = if action.center_cursor {
13161            SelectionEffects::scroll(Autoscroll::center())
13162        } else {
13163            SelectionEffects::default()
13164        };
13165
13166        let text_layout_details = &self.text_layout_details(window);
13167        self.change_selections(effects, window, cx, |s| {
13168            s.move_with(|map, selection| {
13169                if !selection.is_empty() {
13170                    selection.goal = SelectionGoal::None;
13171                }
13172                let (cursor, goal) = movement::down_by_rows(
13173                    map,
13174                    selection.end,
13175                    row_count,
13176                    selection.goal,
13177                    false,
13178                    text_layout_details,
13179                );
13180                selection.collapse_to(cursor, goal);
13181            });
13182        });
13183    }
13184
13185    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13186        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13187        let text_layout_details = &self.text_layout_details(window);
13188        self.change_selections(Default::default(), window, cx, |s| {
13189            s.move_heads_with(|map, head, goal| {
13190                movement::down(map, head, goal, false, text_layout_details)
13191            })
13192        });
13193    }
13194
13195    pub fn context_menu_first(
13196        &mut self,
13197        _: &ContextMenuFirst,
13198        window: &mut Window,
13199        cx: &mut Context<Self>,
13200    ) {
13201        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13202            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13203        }
13204    }
13205
13206    pub fn context_menu_prev(
13207        &mut self,
13208        _: &ContextMenuPrevious,
13209        window: &mut Window,
13210        cx: &mut Context<Self>,
13211    ) {
13212        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13213            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13214        }
13215    }
13216
13217    pub fn context_menu_next(
13218        &mut self,
13219        _: &ContextMenuNext,
13220        window: &mut Window,
13221        cx: &mut Context<Self>,
13222    ) {
13223        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13224            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13225        }
13226    }
13227
13228    pub fn context_menu_last(
13229        &mut self,
13230        _: &ContextMenuLast,
13231        window: &mut Window,
13232        cx: &mut Context<Self>,
13233    ) {
13234        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13235            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13236        }
13237    }
13238
13239    pub fn signature_help_prev(
13240        &mut self,
13241        _: &SignatureHelpPrevious,
13242        _: &mut Window,
13243        cx: &mut Context<Self>,
13244    ) {
13245        if let Some(popover) = self.signature_help_state.popover_mut() {
13246            if popover.current_signature == 0 {
13247                popover.current_signature = popover.signatures.len() - 1;
13248            } else {
13249                popover.current_signature -= 1;
13250            }
13251            cx.notify();
13252        }
13253    }
13254
13255    pub fn signature_help_next(
13256        &mut self,
13257        _: &SignatureHelpNext,
13258        _: &mut Window,
13259        cx: &mut Context<Self>,
13260    ) {
13261        if let Some(popover) = self.signature_help_state.popover_mut() {
13262            if popover.current_signature + 1 == popover.signatures.len() {
13263                popover.current_signature = 0;
13264            } else {
13265                popover.current_signature += 1;
13266            }
13267            cx.notify();
13268        }
13269    }
13270
13271    pub fn move_to_previous_word_start(
13272        &mut self,
13273        _: &MoveToPreviousWordStart,
13274        window: &mut Window,
13275        cx: &mut Context<Self>,
13276    ) {
13277        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13278        self.change_selections(Default::default(), window, cx, |s| {
13279            s.move_cursors_with(|map, head, _| {
13280                (
13281                    movement::previous_word_start(map, head),
13282                    SelectionGoal::None,
13283                )
13284            });
13285        })
13286    }
13287
13288    pub fn move_to_previous_subword_start(
13289        &mut self,
13290        _: &MoveToPreviousSubwordStart,
13291        window: &mut Window,
13292        cx: &mut Context<Self>,
13293    ) {
13294        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13295        self.change_selections(Default::default(), window, cx, |s| {
13296            s.move_cursors_with(|map, head, _| {
13297                (
13298                    movement::previous_subword_start(map, head),
13299                    SelectionGoal::None,
13300                )
13301            });
13302        })
13303    }
13304
13305    pub fn select_to_previous_word_start(
13306        &mut self,
13307        _: &SelectToPreviousWordStart,
13308        window: &mut Window,
13309        cx: &mut Context<Self>,
13310    ) {
13311        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13312        self.change_selections(Default::default(), window, cx, |s| {
13313            s.move_heads_with(|map, head, _| {
13314                (
13315                    movement::previous_word_start(map, head),
13316                    SelectionGoal::None,
13317                )
13318            });
13319        })
13320    }
13321
13322    pub fn select_to_previous_subword_start(
13323        &mut self,
13324        _: &SelectToPreviousSubwordStart,
13325        window: &mut Window,
13326        cx: &mut Context<Self>,
13327    ) {
13328        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13329        self.change_selections(Default::default(), window, cx, |s| {
13330            s.move_heads_with(|map, head, _| {
13331                (
13332                    movement::previous_subword_start(map, head),
13333                    SelectionGoal::None,
13334                )
13335            });
13336        })
13337    }
13338
13339    pub fn delete_to_previous_word_start(
13340        &mut self,
13341        action: &DeleteToPreviousWordStart,
13342        window: &mut Window,
13343        cx: &mut Context<Self>,
13344    ) {
13345        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13346        self.transact(window, cx, |this, window, cx| {
13347            this.select_autoclose_pair(window, cx);
13348            this.change_selections(Default::default(), window, cx, |s| {
13349                s.move_with(|map, selection| {
13350                    if selection.is_empty() {
13351                        let mut cursor = if action.ignore_newlines {
13352                            movement::previous_word_start(map, selection.head())
13353                        } else {
13354                            movement::previous_word_start_or_newline(map, selection.head())
13355                        };
13356                        cursor = movement::adjust_greedy_deletion(
13357                            map,
13358                            selection.head(),
13359                            cursor,
13360                            action.ignore_brackets,
13361                        );
13362                        selection.set_head(cursor, SelectionGoal::None);
13363                    }
13364                });
13365            });
13366            this.insert("", window, cx);
13367        });
13368    }
13369
13370    pub fn delete_to_previous_subword_start(
13371        &mut self,
13372        _: &DeleteToPreviousSubwordStart,
13373        window: &mut Window,
13374        cx: &mut Context<Self>,
13375    ) {
13376        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13377        self.transact(window, cx, |this, window, cx| {
13378            this.select_autoclose_pair(window, cx);
13379            this.change_selections(Default::default(), window, cx, |s| {
13380                s.move_with(|map, selection| {
13381                    if selection.is_empty() {
13382                        let mut cursor = movement::previous_subword_start(map, selection.head());
13383                        cursor =
13384                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13385                        selection.set_head(cursor, SelectionGoal::None);
13386                    }
13387                });
13388            });
13389            this.insert("", window, cx);
13390        });
13391    }
13392
13393    pub fn move_to_next_word_end(
13394        &mut self,
13395        _: &MoveToNextWordEnd,
13396        window: &mut Window,
13397        cx: &mut Context<Self>,
13398    ) {
13399        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13400        self.change_selections(Default::default(), window, cx, |s| {
13401            s.move_cursors_with(|map, head, _| {
13402                (movement::next_word_end(map, head), SelectionGoal::None)
13403            });
13404        })
13405    }
13406
13407    pub fn move_to_next_subword_end(
13408        &mut self,
13409        _: &MoveToNextSubwordEnd,
13410        window: &mut Window,
13411        cx: &mut Context<Self>,
13412    ) {
13413        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13414        self.change_selections(Default::default(), window, cx, |s| {
13415            s.move_cursors_with(|map, head, _| {
13416                (movement::next_subword_end(map, head), SelectionGoal::None)
13417            });
13418        })
13419    }
13420
13421    pub fn select_to_next_word_end(
13422        &mut self,
13423        _: &SelectToNextWordEnd,
13424        window: &mut Window,
13425        cx: &mut Context<Self>,
13426    ) {
13427        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13428        self.change_selections(Default::default(), window, cx, |s| {
13429            s.move_heads_with(|map, head, _| {
13430                (movement::next_word_end(map, head), SelectionGoal::None)
13431            });
13432        })
13433    }
13434
13435    pub fn select_to_next_subword_end(
13436        &mut self,
13437        _: &SelectToNextSubwordEnd,
13438        window: &mut Window,
13439        cx: &mut Context<Self>,
13440    ) {
13441        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13442        self.change_selections(Default::default(), window, cx, |s| {
13443            s.move_heads_with(|map, head, _| {
13444                (movement::next_subword_end(map, head), SelectionGoal::None)
13445            });
13446        })
13447    }
13448
13449    pub fn delete_to_next_word_end(
13450        &mut self,
13451        action: &DeleteToNextWordEnd,
13452        window: &mut Window,
13453        cx: &mut Context<Self>,
13454    ) {
13455        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13456        self.transact(window, cx, |this, window, cx| {
13457            this.change_selections(Default::default(), window, cx, |s| {
13458                s.move_with(|map, selection| {
13459                    if selection.is_empty() {
13460                        let mut cursor = if action.ignore_newlines {
13461                            movement::next_word_end(map, selection.head())
13462                        } else {
13463                            movement::next_word_end_or_newline(map, selection.head())
13464                        };
13465                        cursor = movement::adjust_greedy_deletion(
13466                            map,
13467                            selection.head(),
13468                            cursor,
13469                            action.ignore_brackets,
13470                        );
13471                        selection.set_head(cursor, SelectionGoal::None);
13472                    }
13473                });
13474            });
13475            this.insert("", window, cx);
13476        });
13477    }
13478
13479    pub fn delete_to_next_subword_end(
13480        &mut self,
13481        _: &DeleteToNextSubwordEnd,
13482        window: &mut Window,
13483        cx: &mut Context<Self>,
13484    ) {
13485        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13486        self.transact(window, cx, |this, window, cx| {
13487            this.change_selections(Default::default(), window, cx, |s| {
13488                s.move_with(|map, selection| {
13489                    if selection.is_empty() {
13490                        let mut cursor = movement::next_subword_end(map, selection.head());
13491                        cursor =
13492                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13493                        selection.set_head(cursor, SelectionGoal::None);
13494                    }
13495                });
13496            });
13497            this.insert("", window, cx);
13498        });
13499    }
13500
13501    pub fn move_to_beginning_of_line(
13502        &mut self,
13503        action: &MoveToBeginningOfLine,
13504        window: &mut Window,
13505        cx: &mut Context<Self>,
13506    ) {
13507        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13508        self.change_selections(Default::default(), window, cx, |s| {
13509            s.move_cursors_with(|map, head, _| {
13510                (
13511                    movement::indented_line_beginning(
13512                        map,
13513                        head,
13514                        action.stop_at_soft_wraps,
13515                        action.stop_at_indent,
13516                    ),
13517                    SelectionGoal::None,
13518                )
13519            });
13520        })
13521    }
13522
13523    pub fn select_to_beginning_of_line(
13524        &mut self,
13525        action: &SelectToBeginningOfLine,
13526        window: &mut Window,
13527        cx: &mut Context<Self>,
13528    ) {
13529        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13530        self.change_selections(Default::default(), window, cx, |s| {
13531            s.move_heads_with(|map, head, _| {
13532                (
13533                    movement::indented_line_beginning(
13534                        map,
13535                        head,
13536                        action.stop_at_soft_wraps,
13537                        action.stop_at_indent,
13538                    ),
13539                    SelectionGoal::None,
13540                )
13541            });
13542        });
13543    }
13544
13545    pub fn delete_to_beginning_of_line(
13546        &mut self,
13547        action: &DeleteToBeginningOfLine,
13548        window: &mut Window,
13549        cx: &mut Context<Self>,
13550    ) {
13551        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13552        self.transact(window, cx, |this, window, cx| {
13553            this.change_selections(Default::default(), window, cx, |s| {
13554                s.move_with(|_, selection| {
13555                    selection.reversed = true;
13556                });
13557            });
13558
13559            this.select_to_beginning_of_line(
13560                &SelectToBeginningOfLine {
13561                    stop_at_soft_wraps: false,
13562                    stop_at_indent: action.stop_at_indent,
13563                },
13564                window,
13565                cx,
13566            );
13567            this.backspace(&Backspace, window, cx);
13568        });
13569    }
13570
13571    pub fn move_to_end_of_line(
13572        &mut self,
13573        action: &MoveToEndOfLine,
13574        window: &mut Window,
13575        cx: &mut Context<Self>,
13576    ) {
13577        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13578        self.change_selections(Default::default(), window, cx, |s| {
13579            s.move_cursors_with(|map, head, _| {
13580                (
13581                    movement::line_end(map, head, action.stop_at_soft_wraps),
13582                    SelectionGoal::None,
13583                )
13584            });
13585        })
13586    }
13587
13588    pub fn select_to_end_of_line(
13589        &mut self,
13590        action: &SelectToEndOfLine,
13591        window: &mut Window,
13592        cx: &mut Context<Self>,
13593    ) {
13594        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13595        self.change_selections(Default::default(), window, cx, |s| {
13596            s.move_heads_with(|map, head, _| {
13597                (
13598                    movement::line_end(map, head, action.stop_at_soft_wraps),
13599                    SelectionGoal::None,
13600                )
13601            });
13602        })
13603    }
13604
13605    pub fn delete_to_end_of_line(
13606        &mut self,
13607        _: &DeleteToEndOfLine,
13608        window: &mut Window,
13609        cx: &mut Context<Self>,
13610    ) {
13611        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13612        self.transact(window, cx, |this, window, cx| {
13613            this.select_to_end_of_line(
13614                &SelectToEndOfLine {
13615                    stop_at_soft_wraps: false,
13616                },
13617                window,
13618                cx,
13619            );
13620            this.delete(&Delete, window, cx);
13621        });
13622    }
13623
13624    pub fn cut_to_end_of_line(
13625        &mut self,
13626        action: &CutToEndOfLine,
13627        window: &mut Window,
13628        cx: &mut Context<Self>,
13629    ) {
13630        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13631        self.transact(window, cx, |this, window, cx| {
13632            this.select_to_end_of_line(
13633                &SelectToEndOfLine {
13634                    stop_at_soft_wraps: false,
13635                },
13636                window,
13637                cx,
13638            );
13639            if !action.stop_at_newlines {
13640                this.change_selections(Default::default(), window, cx, |s| {
13641                    s.move_with(|_, sel| {
13642                        if sel.is_empty() {
13643                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13644                        }
13645                    });
13646                });
13647            }
13648            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13649            let item = this.cut_common(false, window, cx);
13650            cx.write_to_clipboard(item);
13651        });
13652    }
13653
13654    pub fn move_to_start_of_paragraph(
13655        &mut self,
13656        _: &MoveToStartOfParagraph,
13657        window: &mut Window,
13658        cx: &mut Context<Self>,
13659    ) {
13660        if matches!(self.mode, EditorMode::SingleLine) {
13661            cx.propagate();
13662            return;
13663        }
13664        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13665        self.change_selections(Default::default(), window, cx, |s| {
13666            s.move_with(|map, selection| {
13667                selection.collapse_to(
13668                    movement::start_of_paragraph(map, selection.head(), 1),
13669                    SelectionGoal::None,
13670                )
13671            });
13672        })
13673    }
13674
13675    pub fn move_to_end_of_paragraph(
13676        &mut self,
13677        _: &MoveToEndOfParagraph,
13678        window: &mut Window,
13679        cx: &mut Context<Self>,
13680    ) {
13681        if matches!(self.mode, EditorMode::SingleLine) {
13682            cx.propagate();
13683            return;
13684        }
13685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13686        self.change_selections(Default::default(), window, cx, |s| {
13687            s.move_with(|map, selection| {
13688                selection.collapse_to(
13689                    movement::end_of_paragraph(map, selection.head(), 1),
13690                    SelectionGoal::None,
13691                )
13692            });
13693        })
13694    }
13695
13696    pub fn select_to_start_of_paragraph(
13697        &mut self,
13698        _: &SelectToStartOfParagraph,
13699        window: &mut Window,
13700        cx: &mut Context<Self>,
13701    ) {
13702        if matches!(self.mode, EditorMode::SingleLine) {
13703            cx.propagate();
13704            return;
13705        }
13706        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13707        self.change_selections(Default::default(), window, cx, |s| {
13708            s.move_heads_with(|map, head, _| {
13709                (
13710                    movement::start_of_paragraph(map, head, 1),
13711                    SelectionGoal::None,
13712                )
13713            });
13714        })
13715    }
13716
13717    pub fn select_to_end_of_paragraph(
13718        &mut self,
13719        _: &SelectToEndOfParagraph,
13720        window: &mut Window,
13721        cx: &mut Context<Self>,
13722    ) {
13723        if matches!(self.mode, EditorMode::SingleLine) {
13724            cx.propagate();
13725            return;
13726        }
13727        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13728        self.change_selections(Default::default(), window, cx, |s| {
13729            s.move_heads_with(|map, head, _| {
13730                (
13731                    movement::end_of_paragraph(map, head, 1),
13732                    SelectionGoal::None,
13733                )
13734            });
13735        })
13736    }
13737
13738    pub fn move_to_start_of_excerpt(
13739        &mut self,
13740        _: &MoveToStartOfExcerpt,
13741        window: &mut Window,
13742        cx: &mut Context<Self>,
13743    ) {
13744        if matches!(self.mode, EditorMode::SingleLine) {
13745            cx.propagate();
13746            return;
13747        }
13748        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13749        self.change_selections(Default::default(), window, cx, |s| {
13750            s.move_with(|map, selection| {
13751                selection.collapse_to(
13752                    movement::start_of_excerpt(
13753                        map,
13754                        selection.head(),
13755                        workspace::searchable::Direction::Prev,
13756                    ),
13757                    SelectionGoal::None,
13758                )
13759            });
13760        })
13761    }
13762
13763    pub fn move_to_start_of_next_excerpt(
13764        &mut self,
13765        _: &MoveToStartOfNextExcerpt,
13766        window: &mut Window,
13767        cx: &mut Context<Self>,
13768    ) {
13769        if matches!(self.mode, EditorMode::SingleLine) {
13770            cx.propagate();
13771            return;
13772        }
13773
13774        self.change_selections(Default::default(), window, cx, |s| {
13775            s.move_with(|map, selection| {
13776                selection.collapse_to(
13777                    movement::start_of_excerpt(
13778                        map,
13779                        selection.head(),
13780                        workspace::searchable::Direction::Next,
13781                    ),
13782                    SelectionGoal::None,
13783                )
13784            });
13785        })
13786    }
13787
13788    pub fn move_to_end_of_excerpt(
13789        &mut self,
13790        _: &MoveToEndOfExcerpt,
13791        window: &mut Window,
13792        cx: &mut Context<Self>,
13793    ) {
13794        if matches!(self.mode, EditorMode::SingleLine) {
13795            cx.propagate();
13796            return;
13797        }
13798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13799        self.change_selections(Default::default(), window, cx, |s| {
13800            s.move_with(|map, selection| {
13801                selection.collapse_to(
13802                    movement::end_of_excerpt(
13803                        map,
13804                        selection.head(),
13805                        workspace::searchable::Direction::Next,
13806                    ),
13807                    SelectionGoal::None,
13808                )
13809            });
13810        })
13811    }
13812
13813    pub fn move_to_end_of_previous_excerpt(
13814        &mut self,
13815        _: &MoveToEndOfPreviousExcerpt,
13816        window: &mut Window,
13817        cx: &mut Context<Self>,
13818    ) {
13819        if matches!(self.mode, EditorMode::SingleLine) {
13820            cx.propagate();
13821            return;
13822        }
13823        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13824        self.change_selections(Default::default(), window, cx, |s| {
13825            s.move_with(|map, selection| {
13826                selection.collapse_to(
13827                    movement::end_of_excerpt(
13828                        map,
13829                        selection.head(),
13830                        workspace::searchable::Direction::Prev,
13831                    ),
13832                    SelectionGoal::None,
13833                )
13834            });
13835        })
13836    }
13837
13838    pub fn select_to_start_of_excerpt(
13839        &mut self,
13840        _: &SelectToStartOfExcerpt,
13841        window: &mut Window,
13842        cx: &mut Context<Self>,
13843    ) {
13844        if matches!(self.mode, EditorMode::SingleLine) {
13845            cx.propagate();
13846            return;
13847        }
13848        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13849        self.change_selections(Default::default(), window, cx, |s| {
13850            s.move_heads_with(|map, head, _| {
13851                (
13852                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13853                    SelectionGoal::None,
13854                )
13855            });
13856        })
13857    }
13858
13859    pub fn select_to_start_of_next_excerpt(
13860        &mut self,
13861        _: &SelectToStartOfNextExcerpt,
13862        window: &mut Window,
13863        cx: &mut Context<Self>,
13864    ) {
13865        if matches!(self.mode, EditorMode::SingleLine) {
13866            cx.propagate();
13867            return;
13868        }
13869        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13870        self.change_selections(Default::default(), window, cx, |s| {
13871            s.move_heads_with(|map, head, _| {
13872                (
13873                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13874                    SelectionGoal::None,
13875                )
13876            });
13877        })
13878    }
13879
13880    pub fn select_to_end_of_excerpt(
13881        &mut self,
13882        _: &SelectToEndOfExcerpt,
13883        window: &mut Window,
13884        cx: &mut Context<Self>,
13885    ) {
13886        if matches!(self.mode, EditorMode::SingleLine) {
13887            cx.propagate();
13888            return;
13889        }
13890        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13891        self.change_selections(Default::default(), window, cx, |s| {
13892            s.move_heads_with(|map, head, _| {
13893                (
13894                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13895                    SelectionGoal::None,
13896                )
13897            });
13898        })
13899    }
13900
13901    pub fn select_to_end_of_previous_excerpt(
13902        &mut self,
13903        _: &SelectToEndOfPreviousExcerpt,
13904        window: &mut Window,
13905        cx: &mut Context<Self>,
13906    ) {
13907        if matches!(self.mode, EditorMode::SingleLine) {
13908            cx.propagate();
13909            return;
13910        }
13911        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13912        self.change_selections(Default::default(), window, cx, |s| {
13913            s.move_heads_with(|map, head, _| {
13914                (
13915                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13916                    SelectionGoal::None,
13917                )
13918            });
13919        })
13920    }
13921
13922    pub fn move_to_beginning(
13923        &mut self,
13924        _: &MoveToBeginning,
13925        window: &mut Window,
13926        cx: &mut Context<Self>,
13927    ) {
13928        if matches!(self.mode, EditorMode::SingleLine) {
13929            cx.propagate();
13930            return;
13931        }
13932        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13933        self.change_selections(Default::default(), window, cx, |s| {
13934            s.select_ranges(vec![0..0]);
13935        });
13936    }
13937
13938    pub fn select_to_beginning(
13939        &mut self,
13940        _: &SelectToBeginning,
13941        window: &mut Window,
13942        cx: &mut Context<Self>,
13943    ) {
13944        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
13945        selection.set_head(Point::zero(), SelectionGoal::None);
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13947        self.change_selections(Default::default(), window, cx, |s| {
13948            s.select(vec![selection]);
13949        });
13950    }
13951
13952    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13953        if matches!(self.mode, EditorMode::SingleLine) {
13954            cx.propagate();
13955            return;
13956        }
13957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13958        let cursor = self.buffer.read(cx).read(cx).len();
13959        self.change_selections(Default::default(), window, cx, |s| {
13960            s.select_ranges(vec![cursor..cursor])
13961        });
13962    }
13963
13964    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13965        self.nav_history = nav_history;
13966    }
13967
13968    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13969        self.nav_history.as_ref()
13970    }
13971
13972    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13973        self.push_to_nav_history(
13974            self.selections.newest_anchor().head(),
13975            None,
13976            false,
13977            true,
13978            cx,
13979        );
13980    }
13981
13982    fn push_to_nav_history(
13983        &mut self,
13984        cursor_anchor: Anchor,
13985        new_position: Option<Point>,
13986        is_deactivate: bool,
13987        always: bool,
13988        cx: &mut Context<Self>,
13989    ) {
13990        if let Some(nav_history) = self.nav_history.as_mut() {
13991            let buffer = self.buffer.read(cx).read(cx);
13992            let cursor_position = cursor_anchor.to_point(&buffer);
13993            let scroll_state = self.scroll_manager.anchor();
13994            let scroll_top_row = scroll_state.top_row(&buffer);
13995            drop(buffer);
13996
13997            if let Some(new_position) = new_position {
13998                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13999                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14000                    return;
14001                }
14002            }
14003
14004            nav_history.push(
14005                Some(NavigationData {
14006                    cursor_anchor,
14007                    cursor_position,
14008                    scroll_anchor: scroll_state,
14009                    scroll_top_row,
14010                }),
14011                cx,
14012            );
14013            cx.emit(EditorEvent::PushedToNavHistory {
14014                anchor: cursor_anchor,
14015                is_deactivate,
14016            })
14017        }
14018    }
14019
14020    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14021        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14022        let buffer = self.buffer.read(cx).snapshot(cx);
14023        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14024        selection.set_head(buffer.len(), SelectionGoal::None);
14025        self.change_selections(Default::default(), window, cx, |s| {
14026            s.select(vec![selection]);
14027        });
14028    }
14029
14030    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14031        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14032        let end = self.buffer.read(cx).read(cx).len();
14033        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14034            s.select_ranges(vec![0..end]);
14035        });
14036    }
14037
14038    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14039        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14040        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14041        let mut selections = self.selections.all::<Point>(&display_map);
14042        let max_point = display_map.buffer_snapshot().max_point();
14043        for selection in &mut selections {
14044            let rows = selection.spanned_rows(true, &display_map);
14045            selection.start = Point::new(rows.start.0, 0);
14046            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14047            selection.reversed = false;
14048        }
14049        self.change_selections(Default::default(), window, cx, |s| {
14050            s.select(selections);
14051        });
14052    }
14053
14054    pub fn split_selection_into_lines(
14055        &mut self,
14056        action: &SplitSelectionIntoLines,
14057        window: &mut Window,
14058        cx: &mut Context<Self>,
14059    ) {
14060        let selections = self
14061            .selections
14062            .all::<Point>(&self.display_snapshot(cx))
14063            .into_iter()
14064            .map(|selection| selection.start..selection.end)
14065            .collect::<Vec<_>>();
14066        self.unfold_ranges(&selections, true, true, cx);
14067
14068        let mut new_selection_ranges = Vec::new();
14069        {
14070            let buffer = self.buffer.read(cx).read(cx);
14071            for selection in selections {
14072                for row in selection.start.row..selection.end.row {
14073                    let line_start = Point::new(row, 0);
14074                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14075
14076                    if action.keep_selections {
14077                        // Keep the selection range for each line
14078                        let selection_start = if row == selection.start.row {
14079                            selection.start
14080                        } else {
14081                            line_start
14082                        };
14083                        new_selection_ranges.push(selection_start..line_end);
14084                    } else {
14085                        // Collapse to cursor at end of line
14086                        new_selection_ranges.push(line_end..line_end);
14087                    }
14088                }
14089
14090                let is_multiline_selection = selection.start.row != selection.end.row;
14091                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14092                // so this action feels more ergonomic when paired with other selection operations
14093                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14094                if !should_skip_last {
14095                    if action.keep_selections {
14096                        if is_multiline_selection {
14097                            let line_start = Point::new(selection.end.row, 0);
14098                            new_selection_ranges.push(line_start..selection.end);
14099                        } else {
14100                            new_selection_ranges.push(selection.start..selection.end);
14101                        }
14102                    } else {
14103                        new_selection_ranges.push(selection.end..selection.end);
14104                    }
14105                }
14106            }
14107        }
14108        self.change_selections(Default::default(), window, cx, |s| {
14109            s.select_ranges(new_selection_ranges);
14110        });
14111    }
14112
14113    pub fn add_selection_above(
14114        &mut self,
14115        action: &AddSelectionAbove,
14116        window: &mut Window,
14117        cx: &mut Context<Self>,
14118    ) {
14119        self.add_selection(true, action.skip_soft_wrap, window, cx);
14120    }
14121
14122    pub fn add_selection_below(
14123        &mut self,
14124        action: &AddSelectionBelow,
14125        window: &mut Window,
14126        cx: &mut Context<Self>,
14127    ) {
14128        self.add_selection(false, action.skip_soft_wrap, window, cx);
14129    }
14130
14131    fn add_selection(
14132        &mut self,
14133        above: bool,
14134        skip_soft_wrap: bool,
14135        window: &mut Window,
14136        cx: &mut Context<Self>,
14137    ) {
14138        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14139
14140        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14141        let all_selections = self.selections.all::<Point>(&display_map);
14142        let text_layout_details = self.text_layout_details(window);
14143
14144        let (mut columnar_selections, new_selections_to_columnarize) = {
14145            if let Some(state) = self.add_selections_state.as_ref() {
14146                let columnar_selection_ids: HashSet<_> = state
14147                    .groups
14148                    .iter()
14149                    .flat_map(|group| group.stack.iter())
14150                    .copied()
14151                    .collect();
14152
14153                all_selections
14154                    .into_iter()
14155                    .partition(|s| columnar_selection_ids.contains(&s.id))
14156            } else {
14157                (Vec::new(), all_selections)
14158            }
14159        };
14160
14161        let mut state = self
14162            .add_selections_state
14163            .take()
14164            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14165
14166        for selection in new_selections_to_columnarize {
14167            let range = selection.display_range(&display_map).sorted();
14168            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14169            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14170            let positions = start_x.min(end_x)..start_x.max(end_x);
14171            let mut stack = Vec::new();
14172            for row in range.start.row().0..=range.end.row().0 {
14173                if let Some(selection) = self.selections.build_columnar_selection(
14174                    &display_map,
14175                    DisplayRow(row),
14176                    &positions,
14177                    selection.reversed,
14178                    &text_layout_details,
14179                ) {
14180                    stack.push(selection.id);
14181                    columnar_selections.push(selection);
14182                }
14183            }
14184            if !stack.is_empty() {
14185                if above {
14186                    stack.reverse();
14187                }
14188                state.groups.push(AddSelectionsGroup { above, stack });
14189            }
14190        }
14191
14192        let mut final_selections = Vec::new();
14193        let end_row = if above {
14194            DisplayRow(0)
14195        } else {
14196            display_map.max_point().row()
14197        };
14198
14199        let mut last_added_item_per_group = HashMap::default();
14200        for group in state.groups.iter_mut() {
14201            if let Some(last_id) = group.stack.last() {
14202                last_added_item_per_group.insert(*last_id, group);
14203            }
14204        }
14205
14206        for selection in columnar_selections {
14207            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14208                if above == group.above {
14209                    let range = selection.display_range(&display_map).sorted();
14210                    debug_assert_eq!(range.start.row(), range.end.row());
14211                    let mut row = range.start.row();
14212                    let positions =
14213                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14214                            Pixels::from(start)..Pixels::from(end)
14215                        } else {
14216                            let start_x =
14217                                display_map.x_for_display_point(range.start, &text_layout_details);
14218                            let end_x =
14219                                display_map.x_for_display_point(range.end, &text_layout_details);
14220                            start_x.min(end_x)..start_x.max(end_x)
14221                        };
14222
14223                    let mut maybe_new_selection = None;
14224                    let direction = if above { -1 } else { 1 };
14225
14226                    while row != end_row {
14227                        if skip_soft_wrap {
14228                            row = display_map
14229                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14230                                .row();
14231                        } else if above {
14232                            row.0 -= 1;
14233                        } else {
14234                            row.0 += 1;
14235                        }
14236
14237                        if let Some(new_selection) = self.selections.build_columnar_selection(
14238                            &display_map,
14239                            row,
14240                            &positions,
14241                            selection.reversed,
14242                            &text_layout_details,
14243                        ) {
14244                            maybe_new_selection = Some(new_selection);
14245                            break;
14246                        }
14247                    }
14248
14249                    if let Some(new_selection) = maybe_new_selection {
14250                        group.stack.push(new_selection.id);
14251                        if above {
14252                            final_selections.push(new_selection);
14253                            final_selections.push(selection);
14254                        } else {
14255                            final_selections.push(selection);
14256                            final_selections.push(new_selection);
14257                        }
14258                    } else {
14259                        final_selections.push(selection);
14260                    }
14261                } else {
14262                    group.stack.pop();
14263                }
14264            } else {
14265                final_selections.push(selection);
14266            }
14267        }
14268
14269        self.change_selections(Default::default(), window, cx, |s| {
14270            s.select(final_selections);
14271        });
14272
14273        let final_selection_ids: HashSet<_> = self
14274            .selections
14275            .all::<Point>(&display_map)
14276            .iter()
14277            .map(|s| s.id)
14278            .collect();
14279        state.groups.retain_mut(|group| {
14280            // selections might get merged above so we remove invalid items from stacks
14281            group.stack.retain(|id| final_selection_ids.contains(id));
14282
14283            // single selection in stack can be treated as initial state
14284            group.stack.len() > 1
14285        });
14286
14287        if !state.groups.is_empty() {
14288            self.add_selections_state = Some(state);
14289        }
14290    }
14291
14292    fn select_match_ranges(
14293        &mut self,
14294        range: Range<usize>,
14295        reversed: bool,
14296        replace_newest: bool,
14297        auto_scroll: Option<Autoscroll>,
14298        window: &mut Window,
14299        cx: &mut Context<Editor>,
14300    ) {
14301        self.unfold_ranges(
14302            std::slice::from_ref(&range),
14303            false,
14304            auto_scroll.is_some(),
14305            cx,
14306        );
14307        let effects = if let Some(scroll) = auto_scroll {
14308            SelectionEffects::scroll(scroll)
14309        } else {
14310            SelectionEffects::no_scroll()
14311        };
14312        self.change_selections(effects, window, cx, |s| {
14313            if replace_newest {
14314                s.delete(s.newest_anchor().id);
14315            }
14316            if reversed {
14317                s.insert_range(range.end..range.start);
14318            } else {
14319                s.insert_range(range);
14320            }
14321        });
14322    }
14323
14324    pub fn select_next_match_internal(
14325        &mut self,
14326        display_map: &DisplaySnapshot,
14327        replace_newest: bool,
14328        autoscroll: Option<Autoscroll>,
14329        window: &mut Window,
14330        cx: &mut Context<Self>,
14331    ) -> Result<()> {
14332        let buffer = display_map.buffer_snapshot();
14333        let mut selections = self.selections.all::<usize>(&display_map);
14334        if let Some(mut select_next_state) = self.select_next_state.take() {
14335            let query = &select_next_state.query;
14336            if !select_next_state.done {
14337                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14338                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14339                let mut next_selected_range = None;
14340
14341                let bytes_after_last_selection =
14342                    buffer.bytes_in_range(last_selection.end..buffer.len());
14343                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14344                let query_matches = query
14345                    .stream_find_iter(bytes_after_last_selection)
14346                    .map(|result| (last_selection.end, result))
14347                    .chain(
14348                        query
14349                            .stream_find_iter(bytes_before_first_selection)
14350                            .map(|result| (0, result)),
14351                    );
14352
14353                for (start_offset, query_match) in query_matches {
14354                    let query_match = query_match.unwrap(); // can only fail due to I/O
14355                    let offset_range =
14356                        start_offset + query_match.start()..start_offset + query_match.end();
14357
14358                    if !select_next_state.wordwise
14359                        || (!buffer.is_inside_word(offset_range.start, None)
14360                            && !buffer.is_inside_word(offset_range.end, None))
14361                    {
14362                        let idx = selections
14363                            .partition_point(|selection| selection.end <= offset_range.start);
14364                        let overlaps = selections
14365                            .get(idx)
14366                            .map_or(false, |selection| selection.start < offset_range.end);
14367
14368                        if !overlaps {
14369                            next_selected_range = Some(offset_range);
14370                            break;
14371                        }
14372                    }
14373                }
14374
14375                if let Some(next_selected_range) = next_selected_range {
14376                    self.select_match_ranges(
14377                        next_selected_range,
14378                        last_selection.reversed,
14379                        replace_newest,
14380                        autoscroll,
14381                        window,
14382                        cx,
14383                    );
14384                } else {
14385                    select_next_state.done = true;
14386                }
14387            }
14388
14389            self.select_next_state = Some(select_next_state);
14390        } else {
14391            let mut only_carets = true;
14392            let mut same_text_selected = true;
14393            let mut selected_text = None;
14394
14395            let mut selections_iter = selections.iter().peekable();
14396            while let Some(selection) = selections_iter.next() {
14397                if selection.start != selection.end {
14398                    only_carets = false;
14399                }
14400
14401                if same_text_selected {
14402                    if selected_text.is_none() {
14403                        selected_text =
14404                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14405                    }
14406
14407                    if let Some(next_selection) = selections_iter.peek() {
14408                        if next_selection.range().len() == selection.range().len() {
14409                            let next_selected_text = buffer
14410                                .text_for_range(next_selection.range())
14411                                .collect::<String>();
14412                            if Some(next_selected_text) != selected_text {
14413                                same_text_selected = false;
14414                                selected_text = None;
14415                            }
14416                        } else {
14417                            same_text_selected = false;
14418                            selected_text = None;
14419                        }
14420                    }
14421                }
14422            }
14423
14424            if only_carets {
14425                for selection in &mut selections {
14426                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14427                    selection.start = word_range.start;
14428                    selection.end = word_range.end;
14429                    selection.goal = SelectionGoal::None;
14430                    selection.reversed = false;
14431                    self.select_match_ranges(
14432                        selection.start..selection.end,
14433                        selection.reversed,
14434                        replace_newest,
14435                        autoscroll,
14436                        window,
14437                        cx,
14438                    );
14439                }
14440
14441                if selections.len() == 1 {
14442                    let selection = selections
14443                        .last()
14444                        .expect("ensured that there's only one selection");
14445                    let query = buffer
14446                        .text_for_range(selection.start..selection.end)
14447                        .collect::<String>();
14448                    let is_empty = query.is_empty();
14449                    let select_state = SelectNextState {
14450                        query: AhoCorasick::new(&[query])?,
14451                        wordwise: true,
14452                        done: is_empty,
14453                    };
14454                    self.select_next_state = Some(select_state);
14455                } else {
14456                    self.select_next_state = None;
14457                }
14458            } else if let Some(selected_text) = selected_text {
14459                self.select_next_state = Some(SelectNextState {
14460                    query: AhoCorasick::new(&[selected_text])?,
14461                    wordwise: false,
14462                    done: false,
14463                });
14464                self.select_next_match_internal(
14465                    display_map,
14466                    replace_newest,
14467                    autoscroll,
14468                    window,
14469                    cx,
14470                )?;
14471            }
14472        }
14473        Ok(())
14474    }
14475
14476    pub fn select_all_matches(
14477        &mut self,
14478        _action: &SelectAllMatches,
14479        window: &mut Window,
14480        cx: &mut Context<Self>,
14481    ) -> Result<()> {
14482        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14483
14484        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14485
14486        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14487        let Some(select_next_state) = self.select_next_state.as_mut() else {
14488            return Ok(());
14489        };
14490        if select_next_state.done {
14491            return Ok(());
14492        }
14493
14494        let mut new_selections = Vec::new();
14495
14496        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14497        let buffer = display_map.buffer_snapshot();
14498        let query_matches = select_next_state
14499            .query
14500            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14501
14502        for query_match in query_matches.into_iter() {
14503            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14504            let offset_range = if reversed {
14505                query_match.end()..query_match.start()
14506            } else {
14507                query_match.start()..query_match.end()
14508            };
14509
14510            if !select_next_state.wordwise
14511                || (!buffer.is_inside_word(offset_range.start, None)
14512                    && !buffer.is_inside_word(offset_range.end, None))
14513            {
14514                new_selections.push(offset_range.start..offset_range.end);
14515            }
14516        }
14517
14518        select_next_state.done = true;
14519
14520        if new_selections.is_empty() {
14521            log::error!("bug: new_selections is empty in select_all_matches");
14522            return Ok(());
14523        }
14524
14525        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14526        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14527            selections.select_ranges(new_selections)
14528        });
14529
14530        Ok(())
14531    }
14532
14533    pub fn select_next(
14534        &mut self,
14535        action: &SelectNext,
14536        window: &mut Window,
14537        cx: &mut Context<Self>,
14538    ) -> Result<()> {
14539        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14540        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14541        self.select_next_match_internal(
14542            &display_map,
14543            action.replace_newest,
14544            Some(Autoscroll::newest()),
14545            window,
14546            cx,
14547        )?;
14548        Ok(())
14549    }
14550
14551    pub fn select_previous(
14552        &mut self,
14553        action: &SelectPrevious,
14554        window: &mut Window,
14555        cx: &mut Context<Self>,
14556    ) -> Result<()> {
14557        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14558        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14559        let buffer = display_map.buffer_snapshot();
14560        let mut selections = self.selections.all::<usize>(&display_map);
14561        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14562            let query = &select_prev_state.query;
14563            if !select_prev_state.done {
14564                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14565                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14566                let mut next_selected_range = None;
14567                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14568                let bytes_before_last_selection =
14569                    buffer.reversed_bytes_in_range(0..last_selection.start);
14570                let bytes_after_first_selection =
14571                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14572                let query_matches = query
14573                    .stream_find_iter(bytes_before_last_selection)
14574                    .map(|result| (last_selection.start, result))
14575                    .chain(
14576                        query
14577                            .stream_find_iter(bytes_after_first_selection)
14578                            .map(|result| (buffer.len(), result)),
14579                    );
14580                for (end_offset, query_match) in query_matches {
14581                    let query_match = query_match.unwrap(); // can only fail due to I/O
14582                    let offset_range =
14583                        end_offset - query_match.end()..end_offset - query_match.start();
14584
14585                    if !select_prev_state.wordwise
14586                        || (!buffer.is_inside_word(offset_range.start, None)
14587                            && !buffer.is_inside_word(offset_range.end, None))
14588                    {
14589                        next_selected_range = Some(offset_range);
14590                        break;
14591                    }
14592                }
14593
14594                if let Some(next_selected_range) = next_selected_range {
14595                    self.select_match_ranges(
14596                        next_selected_range,
14597                        last_selection.reversed,
14598                        action.replace_newest,
14599                        Some(Autoscroll::newest()),
14600                        window,
14601                        cx,
14602                    );
14603                } else {
14604                    select_prev_state.done = true;
14605                }
14606            }
14607
14608            self.select_prev_state = Some(select_prev_state);
14609        } else {
14610            let mut only_carets = true;
14611            let mut same_text_selected = true;
14612            let mut selected_text = None;
14613
14614            let mut selections_iter = selections.iter().peekable();
14615            while let Some(selection) = selections_iter.next() {
14616                if selection.start != selection.end {
14617                    only_carets = false;
14618                }
14619
14620                if same_text_selected {
14621                    if selected_text.is_none() {
14622                        selected_text =
14623                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14624                    }
14625
14626                    if let Some(next_selection) = selections_iter.peek() {
14627                        if next_selection.range().len() == selection.range().len() {
14628                            let next_selected_text = buffer
14629                                .text_for_range(next_selection.range())
14630                                .collect::<String>();
14631                            if Some(next_selected_text) != selected_text {
14632                                same_text_selected = false;
14633                                selected_text = None;
14634                            }
14635                        } else {
14636                            same_text_selected = false;
14637                            selected_text = None;
14638                        }
14639                    }
14640                }
14641            }
14642
14643            if only_carets {
14644                for selection in &mut selections {
14645                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14646                    selection.start = word_range.start;
14647                    selection.end = word_range.end;
14648                    selection.goal = SelectionGoal::None;
14649                    selection.reversed = false;
14650                    self.select_match_ranges(
14651                        selection.start..selection.end,
14652                        selection.reversed,
14653                        action.replace_newest,
14654                        Some(Autoscroll::newest()),
14655                        window,
14656                        cx,
14657                    );
14658                }
14659                if selections.len() == 1 {
14660                    let selection = selections
14661                        .last()
14662                        .expect("ensured that there's only one selection");
14663                    let query = buffer
14664                        .text_for_range(selection.start..selection.end)
14665                        .collect::<String>();
14666                    let is_empty = query.is_empty();
14667                    let select_state = SelectNextState {
14668                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14669                        wordwise: true,
14670                        done: is_empty,
14671                    };
14672                    self.select_prev_state = Some(select_state);
14673                } else {
14674                    self.select_prev_state = None;
14675                }
14676            } else if let Some(selected_text) = selected_text {
14677                self.select_prev_state = Some(SelectNextState {
14678                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14679                    wordwise: false,
14680                    done: false,
14681                });
14682                self.select_previous(action, window, cx)?;
14683            }
14684        }
14685        Ok(())
14686    }
14687
14688    pub fn find_next_match(
14689        &mut self,
14690        _: &FindNextMatch,
14691        window: &mut Window,
14692        cx: &mut Context<Self>,
14693    ) -> Result<()> {
14694        let selections = self.selections.disjoint_anchors_arc();
14695        match selections.first() {
14696            Some(first) if selections.len() >= 2 => {
14697                self.change_selections(Default::default(), window, cx, |s| {
14698                    s.select_ranges([first.range()]);
14699                });
14700            }
14701            _ => self.select_next(
14702                &SelectNext {
14703                    replace_newest: true,
14704                },
14705                window,
14706                cx,
14707            )?,
14708        }
14709        Ok(())
14710    }
14711
14712    pub fn find_previous_match(
14713        &mut self,
14714        _: &FindPreviousMatch,
14715        window: &mut Window,
14716        cx: &mut Context<Self>,
14717    ) -> Result<()> {
14718        let selections = self.selections.disjoint_anchors_arc();
14719        match selections.last() {
14720            Some(last) if selections.len() >= 2 => {
14721                self.change_selections(Default::default(), window, cx, |s| {
14722                    s.select_ranges([last.range()]);
14723                });
14724            }
14725            _ => self.select_previous(
14726                &SelectPrevious {
14727                    replace_newest: true,
14728                },
14729                window,
14730                cx,
14731            )?,
14732        }
14733        Ok(())
14734    }
14735
14736    pub fn toggle_comments(
14737        &mut self,
14738        action: &ToggleComments,
14739        window: &mut Window,
14740        cx: &mut Context<Self>,
14741    ) {
14742        if self.read_only(cx) {
14743            return;
14744        }
14745        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14746        let text_layout_details = &self.text_layout_details(window);
14747        self.transact(window, cx, |this, window, cx| {
14748            let mut selections = this
14749                .selections
14750                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14751            let mut edits = Vec::new();
14752            let mut selection_edit_ranges = Vec::new();
14753            let mut last_toggled_row = None;
14754            let snapshot = this.buffer.read(cx).read(cx);
14755            let empty_str: Arc<str> = Arc::default();
14756            let mut suffixes_inserted = Vec::new();
14757            let ignore_indent = action.ignore_indent;
14758
14759            fn comment_prefix_range(
14760                snapshot: &MultiBufferSnapshot,
14761                row: MultiBufferRow,
14762                comment_prefix: &str,
14763                comment_prefix_whitespace: &str,
14764                ignore_indent: bool,
14765            ) -> Range<Point> {
14766                let indent_size = if ignore_indent {
14767                    0
14768                } else {
14769                    snapshot.indent_size_for_line(row).len
14770                };
14771
14772                let start = Point::new(row.0, indent_size);
14773
14774                let mut line_bytes = snapshot
14775                    .bytes_in_range(start..snapshot.max_point())
14776                    .flatten()
14777                    .copied();
14778
14779                // If this line currently begins with the line comment prefix, then record
14780                // the range containing the prefix.
14781                if line_bytes
14782                    .by_ref()
14783                    .take(comment_prefix.len())
14784                    .eq(comment_prefix.bytes())
14785                {
14786                    // Include any whitespace that matches the comment prefix.
14787                    let matching_whitespace_len = line_bytes
14788                        .zip(comment_prefix_whitespace.bytes())
14789                        .take_while(|(a, b)| a == b)
14790                        .count() as u32;
14791                    let end = Point::new(
14792                        start.row,
14793                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14794                    );
14795                    start..end
14796                } else {
14797                    start..start
14798                }
14799            }
14800
14801            fn comment_suffix_range(
14802                snapshot: &MultiBufferSnapshot,
14803                row: MultiBufferRow,
14804                comment_suffix: &str,
14805                comment_suffix_has_leading_space: bool,
14806            ) -> Range<Point> {
14807                let end = Point::new(row.0, snapshot.line_len(row));
14808                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14809
14810                let mut line_end_bytes = snapshot
14811                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14812                    .flatten()
14813                    .copied();
14814
14815                let leading_space_len = if suffix_start_column > 0
14816                    && line_end_bytes.next() == Some(b' ')
14817                    && comment_suffix_has_leading_space
14818                {
14819                    1
14820                } else {
14821                    0
14822                };
14823
14824                // If this line currently begins with the line comment prefix, then record
14825                // the range containing the prefix.
14826                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14827                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14828                    start..end
14829                } else {
14830                    end..end
14831                }
14832            }
14833
14834            // TODO: Handle selections that cross excerpts
14835            for selection in &mut selections {
14836                let start_column = snapshot
14837                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14838                    .len;
14839                let language = if let Some(language) =
14840                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14841                {
14842                    language
14843                } else {
14844                    continue;
14845                };
14846
14847                selection_edit_ranges.clear();
14848
14849                // If multiple selections contain a given row, avoid processing that
14850                // row more than once.
14851                let mut start_row = MultiBufferRow(selection.start.row);
14852                if last_toggled_row == Some(start_row) {
14853                    start_row = start_row.next_row();
14854                }
14855                let end_row =
14856                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14857                        MultiBufferRow(selection.end.row - 1)
14858                    } else {
14859                        MultiBufferRow(selection.end.row)
14860                    };
14861                last_toggled_row = Some(end_row);
14862
14863                if start_row > end_row {
14864                    continue;
14865                }
14866
14867                // If the language has line comments, toggle those.
14868                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14869
14870                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14871                if ignore_indent {
14872                    full_comment_prefixes = full_comment_prefixes
14873                        .into_iter()
14874                        .map(|s| Arc::from(s.trim_end()))
14875                        .collect();
14876                }
14877
14878                if !full_comment_prefixes.is_empty() {
14879                    let first_prefix = full_comment_prefixes
14880                        .first()
14881                        .expect("prefixes is non-empty");
14882                    let prefix_trimmed_lengths = full_comment_prefixes
14883                        .iter()
14884                        .map(|p| p.trim_end_matches(' ').len())
14885                        .collect::<SmallVec<[usize; 4]>>();
14886
14887                    let mut all_selection_lines_are_comments = true;
14888
14889                    for row in start_row.0..=end_row.0 {
14890                        let row = MultiBufferRow(row);
14891                        if start_row < end_row && snapshot.is_line_blank(row) {
14892                            continue;
14893                        }
14894
14895                        let prefix_range = full_comment_prefixes
14896                            .iter()
14897                            .zip(prefix_trimmed_lengths.iter().copied())
14898                            .map(|(prefix, trimmed_prefix_len)| {
14899                                comment_prefix_range(
14900                                    snapshot.deref(),
14901                                    row,
14902                                    &prefix[..trimmed_prefix_len],
14903                                    &prefix[trimmed_prefix_len..],
14904                                    ignore_indent,
14905                                )
14906                            })
14907                            .max_by_key(|range| range.end.column - range.start.column)
14908                            .expect("prefixes is non-empty");
14909
14910                        if prefix_range.is_empty() {
14911                            all_selection_lines_are_comments = false;
14912                        }
14913
14914                        selection_edit_ranges.push(prefix_range);
14915                    }
14916
14917                    if all_selection_lines_are_comments {
14918                        edits.extend(
14919                            selection_edit_ranges
14920                                .iter()
14921                                .cloned()
14922                                .map(|range| (range, empty_str.clone())),
14923                        );
14924                    } else {
14925                        let min_column = selection_edit_ranges
14926                            .iter()
14927                            .map(|range| range.start.column)
14928                            .min()
14929                            .unwrap_or(0);
14930                        edits.extend(selection_edit_ranges.iter().map(|range| {
14931                            let position = Point::new(range.start.row, min_column);
14932                            (position..position, first_prefix.clone())
14933                        }));
14934                    }
14935                } else if let Some(BlockCommentConfig {
14936                    start: full_comment_prefix,
14937                    end: comment_suffix,
14938                    ..
14939                }) = language.block_comment()
14940                {
14941                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14942                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14943                    let prefix_range = comment_prefix_range(
14944                        snapshot.deref(),
14945                        start_row,
14946                        comment_prefix,
14947                        comment_prefix_whitespace,
14948                        ignore_indent,
14949                    );
14950                    let suffix_range = comment_suffix_range(
14951                        snapshot.deref(),
14952                        end_row,
14953                        comment_suffix.trim_start_matches(' '),
14954                        comment_suffix.starts_with(' '),
14955                    );
14956
14957                    if prefix_range.is_empty() || suffix_range.is_empty() {
14958                        edits.push((
14959                            prefix_range.start..prefix_range.start,
14960                            full_comment_prefix.clone(),
14961                        ));
14962                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14963                        suffixes_inserted.push((end_row, comment_suffix.len()));
14964                    } else {
14965                        edits.push((prefix_range, empty_str.clone()));
14966                        edits.push((suffix_range, empty_str.clone()));
14967                    }
14968                } else {
14969                    continue;
14970                }
14971            }
14972
14973            drop(snapshot);
14974            this.buffer.update(cx, |buffer, cx| {
14975                buffer.edit(edits, None, cx);
14976            });
14977
14978            // Adjust selections so that they end before any comment suffixes that
14979            // were inserted.
14980            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14981            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
14982            let snapshot = this.buffer.read(cx).read(cx);
14983            for selection in &mut selections {
14984                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14985                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14986                        Ordering::Less => {
14987                            suffixes_inserted.next();
14988                            continue;
14989                        }
14990                        Ordering::Greater => break,
14991                        Ordering::Equal => {
14992                            if selection.end.column == snapshot.line_len(row) {
14993                                if selection.is_empty() {
14994                                    selection.start.column -= suffix_len as u32;
14995                                }
14996                                selection.end.column -= suffix_len as u32;
14997                            }
14998                            break;
14999                        }
15000                    }
15001                }
15002            }
15003
15004            drop(snapshot);
15005            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15006
15007            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15008            let selections_on_single_row = selections.windows(2).all(|selections| {
15009                selections[0].start.row == selections[1].start.row
15010                    && selections[0].end.row == selections[1].end.row
15011                    && selections[0].start.row == selections[0].end.row
15012            });
15013            let selections_selecting = selections
15014                .iter()
15015                .any(|selection| selection.start != selection.end);
15016            let advance_downwards = action.advance_downwards
15017                && selections_on_single_row
15018                && !selections_selecting
15019                && !matches!(this.mode, EditorMode::SingleLine);
15020
15021            if advance_downwards {
15022                let snapshot = this.buffer.read(cx).snapshot(cx);
15023
15024                this.change_selections(Default::default(), window, cx, |s| {
15025                    s.move_cursors_with(|display_snapshot, display_point, _| {
15026                        let mut point = display_point.to_point(display_snapshot);
15027                        point.row += 1;
15028                        point = snapshot.clip_point(point, Bias::Left);
15029                        let display_point = point.to_display_point(display_snapshot);
15030                        let goal = SelectionGoal::HorizontalPosition(
15031                            display_snapshot
15032                                .x_for_display_point(display_point, text_layout_details)
15033                                .into(),
15034                        );
15035                        (display_point, goal)
15036                    })
15037                });
15038            }
15039        });
15040    }
15041
15042    pub fn select_enclosing_symbol(
15043        &mut self,
15044        _: &SelectEnclosingSymbol,
15045        window: &mut Window,
15046        cx: &mut Context<Self>,
15047    ) {
15048        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15049
15050        let buffer = self.buffer.read(cx).snapshot(cx);
15051        let old_selections = self
15052            .selections
15053            .all::<usize>(&self.display_snapshot(cx))
15054            .into_boxed_slice();
15055
15056        fn update_selection(
15057            selection: &Selection<usize>,
15058            buffer_snap: &MultiBufferSnapshot,
15059        ) -> Option<Selection<usize>> {
15060            let cursor = selection.head();
15061            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15062            for symbol in symbols.iter().rev() {
15063                let start = symbol.range.start.to_offset(buffer_snap);
15064                let end = symbol.range.end.to_offset(buffer_snap);
15065                let new_range = start..end;
15066                if start < selection.start || end > selection.end {
15067                    return Some(Selection {
15068                        id: selection.id,
15069                        start: new_range.start,
15070                        end: new_range.end,
15071                        goal: SelectionGoal::None,
15072                        reversed: selection.reversed,
15073                    });
15074                }
15075            }
15076            None
15077        }
15078
15079        let mut selected_larger_symbol = false;
15080        let new_selections = old_selections
15081            .iter()
15082            .map(|selection| match update_selection(selection, &buffer) {
15083                Some(new_selection) => {
15084                    if new_selection.range() != selection.range() {
15085                        selected_larger_symbol = true;
15086                    }
15087                    new_selection
15088                }
15089                None => selection.clone(),
15090            })
15091            .collect::<Vec<_>>();
15092
15093        if selected_larger_symbol {
15094            self.change_selections(Default::default(), window, cx, |s| {
15095                s.select(new_selections);
15096            });
15097        }
15098    }
15099
15100    pub fn select_larger_syntax_node(
15101        &mut self,
15102        _: &SelectLargerSyntaxNode,
15103        window: &mut Window,
15104        cx: &mut Context<Self>,
15105    ) {
15106        let Some(visible_row_count) = self.visible_row_count() else {
15107            return;
15108        };
15109        let old_selections: Box<[_]> = self
15110            .selections
15111            .all::<usize>(&self.display_snapshot(cx))
15112            .into();
15113        if old_selections.is_empty() {
15114            return;
15115        }
15116
15117        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15118
15119        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15120        let buffer = self.buffer.read(cx).snapshot(cx);
15121
15122        let mut selected_larger_node = false;
15123        let mut new_selections = old_selections
15124            .iter()
15125            .map(|selection| {
15126                let old_range = selection.start..selection.end;
15127
15128                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15129                    // manually select word at selection
15130                    if ["string_content", "inline"].contains(&node.kind()) {
15131                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15132                        // ignore if word is already selected
15133                        if !word_range.is_empty() && old_range != word_range {
15134                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15135                            // only select word if start and end point belongs to same word
15136                            if word_range == last_word_range {
15137                                selected_larger_node = true;
15138                                return Selection {
15139                                    id: selection.id,
15140                                    start: word_range.start,
15141                                    end: word_range.end,
15142                                    goal: SelectionGoal::None,
15143                                    reversed: selection.reversed,
15144                                };
15145                            }
15146                        }
15147                    }
15148                }
15149
15150                let mut new_range = old_range.clone();
15151                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15152                    new_range = range;
15153                    if !node.is_named() {
15154                        continue;
15155                    }
15156                    if !display_map.intersects_fold(new_range.start)
15157                        && !display_map.intersects_fold(new_range.end)
15158                    {
15159                        break;
15160                    }
15161                }
15162
15163                selected_larger_node |= new_range != old_range;
15164                Selection {
15165                    id: selection.id,
15166                    start: new_range.start,
15167                    end: new_range.end,
15168                    goal: SelectionGoal::None,
15169                    reversed: selection.reversed,
15170                }
15171            })
15172            .collect::<Vec<_>>();
15173
15174        if !selected_larger_node {
15175            return; // don't put this call in the history
15176        }
15177
15178        // scroll based on transformation done to the last selection created by the user
15179        let (last_old, last_new) = old_selections
15180            .last()
15181            .zip(new_selections.last().cloned())
15182            .expect("old_selections isn't empty");
15183
15184        // revert selection
15185        let is_selection_reversed = {
15186            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15187            new_selections.last_mut().expect("checked above").reversed =
15188                should_newest_selection_be_reversed;
15189            should_newest_selection_be_reversed
15190        };
15191
15192        if selected_larger_node {
15193            self.select_syntax_node_history.disable_clearing = true;
15194            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15195                s.select(new_selections.clone());
15196            });
15197            self.select_syntax_node_history.disable_clearing = false;
15198        }
15199
15200        let start_row = last_new.start.to_display_point(&display_map).row().0;
15201        let end_row = last_new.end.to_display_point(&display_map).row().0;
15202        let selection_height = end_row - start_row + 1;
15203        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15204
15205        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15206        let scroll_behavior = if fits_on_the_screen {
15207            self.request_autoscroll(Autoscroll::fit(), cx);
15208            SelectSyntaxNodeScrollBehavior::FitSelection
15209        } else if is_selection_reversed {
15210            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15211            SelectSyntaxNodeScrollBehavior::CursorTop
15212        } else {
15213            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15214            SelectSyntaxNodeScrollBehavior::CursorBottom
15215        };
15216
15217        self.select_syntax_node_history.push((
15218            old_selections,
15219            scroll_behavior,
15220            is_selection_reversed,
15221        ));
15222    }
15223
15224    pub fn select_smaller_syntax_node(
15225        &mut self,
15226        _: &SelectSmallerSyntaxNode,
15227        window: &mut Window,
15228        cx: &mut Context<Self>,
15229    ) {
15230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15231
15232        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15233            self.select_syntax_node_history.pop()
15234        {
15235            if let Some(selection) = selections.last_mut() {
15236                selection.reversed = is_selection_reversed;
15237            }
15238
15239            self.select_syntax_node_history.disable_clearing = true;
15240            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15241                s.select(selections.to_vec());
15242            });
15243            self.select_syntax_node_history.disable_clearing = false;
15244
15245            match scroll_behavior {
15246                SelectSyntaxNodeScrollBehavior::CursorTop => {
15247                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15248                }
15249                SelectSyntaxNodeScrollBehavior::FitSelection => {
15250                    self.request_autoscroll(Autoscroll::fit(), cx);
15251                }
15252                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15253                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15254                }
15255            }
15256        }
15257    }
15258
15259    pub fn unwrap_syntax_node(
15260        &mut self,
15261        _: &UnwrapSyntaxNode,
15262        window: &mut Window,
15263        cx: &mut Context<Self>,
15264    ) {
15265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15266
15267        let buffer = self.buffer.read(cx).snapshot(cx);
15268        let selections = self
15269            .selections
15270            .all::<usize>(&self.display_snapshot(cx))
15271            .into_iter()
15272            // subtracting the offset requires sorting
15273            .sorted_by_key(|i| i.start);
15274
15275        let full_edits = selections
15276            .into_iter()
15277            .filter_map(|selection| {
15278                let child = if selection.is_empty()
15279                    && let Some((_, ancestor_range)) =
15280                        buffer.syntax_ancestor(selection.start..selection.end)
15281                {
15282                    ancestor_range
15283                } else {
15284                    selection.range()
15285                };
15286
15287                let mut parent = child.clone();
15288                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15289                    parent = ancestor_range;
15290                    if parent.start < child.start || parent.end > child.end {
15291                        break;
15292                    }
15293                }
15294
15295                if parent == child {
15296                    return None;
15297                }
15298                let text = buffer.text_for_range(child).collect::<String>();
15299                Some((selection.id, parent, text))
15300            })
15301            .collect::<Vec<_>>();
15302        if full_edits.is_empty() {
15303            return;
15304        }
15305
15306        self.transact(window, cx, |this, window, cx| {
15307            this.buffer.update(cx, |buffer, cx| {
15308                buffer.edit(
15309                    full_edits
15310                        .iter()
15311                        .map(|(_, p, t)| (p.clone(), t.clone()))
15312                        .collect::<Vec<_>>(),
15313                    None,
15314                    cx,
15315                );
15316            });
15317            this.change_selections(Default::default(), window, cx, |s| {
15318                let mut offset = 0;
15319                let mut selections = vec![];
15320                for (id, parent, text) in full_edits {
15321                    let start = parent.start - offset;
15322                    offset += parent.len() - text.len();
15323                    selections.push(Selection {
15324                        id,
15325                        start,
15326                        end: start + text.len(),
15327                        reversed: false,
15328                        goal: Default::default(),
15329                    });
15330                }
15331                s.select(selections);
15332            });
15333        });
15334    }
15335
15336    pub fn select_next_syntax_node(
15337        &mut self,
15338        _: &SelectNextSyntaxNode,
15339        window: &mut Window,
15340        cx: &mut Context<Self>,
15341    ) {
15342        let old_selections: Box<[_]> = self
15343            .selections
15344            .all::<usize>(&self.display_snapshot(cx))
15345            .into();
15346        if old_selections.is_empty() {
15347            return;
15348        }
15349
15350        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15351
15352        let buffer = self.buffer.read(cx).snapshot(cx);
15353        let mut selected_sibling = false;
15354
15355        let new_selections = old_selections
15356            .iter()
15357            .map(|selection| {
15358                let old_range = selection.start..selection.end;
15359
15360                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15361                    let new_range = node.byte_range();
15362                    selected_sibling = true;
15363                    Selection {
15364                        id: selection.id,
15365                        start: new_range.start,
15366                        end: new_range.end,
15367                        goal: SelectionGoal::None,
15368                        reversed: selection.reversed,
15369                    }
15370                } else {
15371                    selection.clone()
15372                }
15373            })
15374            .collect::<Vec<_>>();
15375
15376        if selected_sibling {
15377            self.change_selections(
15378                SelectionEffects::scroll(Autoscroll::fit()),
15379                window,
15380                cx,
15381                |s| {
15382                    s.select(new_selections);
15383                },
15384            );
15385        }
15386    }
15387
15388    pub fn select_prev_syntax_node(
15389        &mut self,
15390        _: &SelectPreviousSyntaxNode,
15391        window: &mut Window,
15392        cx: &mut Context<Self>,
15393    ) {
15394        let old_selections: Box<[_]> = self
15395            .selections
15396            .all::<usize>(&self.display_snapshot(cx))
15397            .into();
15398        if old_selections.is_empty() {
15399            return;
15400        }
15401
15402        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15403
15404        let buffer = self.buffer.read(cx).snapshot(cx);
15405        let mut selected_sibling = false;
15406
15407        let new_selections = old_selections
15408            .iter()
15409            .map(|selection| {
15410                let old_range = selection.start..selection.end;
15411
15412                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15413                    let new_range = node.byte_range();
15414                    selected_sibling = true;
15415                    Selection {
15416                        id: selection.id,
15417                        start: new_range.start,
15418                        end: new_range.end,
15419                        goal: SelectionGoal::None,
15420                        reversed: selection.reversed,
15421                    }
15422                } else {
15423                    selection.clone()
15424                }
15425            })
15426            .collect::<Vec<_>>();
15427
15428        if selected_sibling {
15429            self.change_selections(
15430                SelectionEffects::scroll(Autoscroll::fit()),
15431                window,
15432                cx,
15433                |s| {
15434                    s.select(new_selections);
15435                },
15436            );
15437        }
15438    }
15439
15440    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15441        if !EditorSettings::get_global(cx).gutter.runnables {
15442            self.clear_tasks();
15443            return Task::ready(());
15444        }
15445        let project = self.project().map(Entity::downgrade);
15446        let task_sources = self.lsp_task_sources(cx);
15447        let multi_buffer = self.buffer.downgrade();
15448        cx.spawn_in(window, async move |editor, cx| {
15449            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15450            let Some(project) = project.and_then(|p| p.upgrade()) else {
15451                return;
15452            };
15453            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15454                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15455            }) else {
15456                return;
15457            };
15458
15459            let hide_runnables = project
15460                .update(cx, |project, _| project.is_via_collab())
15461                .unwrap_or(true);
15462            if hide_runnables {
15463                return;
15464            }
15465            let new_rows =
15466                cx.background_spawn({
15467                    let snapshot = display_snapshot.clone();
15468                    async move {
15469                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15470                    }
15471                })
15472                    .await;
15473            let Ok(lsp_tasks) =
15474                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15475            else {
15476                return;
15477            };
15478            let lsp_tasks = lsp_tasks.await;
15479
15480            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15481                lsp_tasks
15482                    .into_iter()
15483                    .flat_map(|(kind, tasks)| {
15484                        tasks.into_iter().filter_map(move |(location, task)| {
15485                            Some((kind.clone(), location?, task))
15486                        })
15487                    })
15488                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15489                        let buffer = location.target.buffer;
15490                        let buffer_snapshot = buffer.read(cx).snapshot();
15491                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15492                            |(excerpt_id, snapshot, _)| {
15493                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15494                                    display_snapshot
15495                                        .buffer_snapshot()
15496                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15497                                } else {
15498                                    None
15499                                }
15500                            },
15501                        );
15502                        if let Some(offset) = offset {
15503                            let task_buffer_range =
15504                                location.target.range.to_point(&buffer_snapshot);
15505                            let context_buffer_range =
15506                                task_buffer_range.to_offset(&buffer_snapshot);
15507                            let context_range = BufferOffset(context_buffer_range.start)
15508                                ..BufferOffset(context_buffer_range.end);
15509
15510                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15511                                .or_insert_with(|| RunnableTasks {
15512                                    templates: Vec::new(),
15513                                    offset,
15514                                    column: task_buffer_range.start.column,
15515                                    extra_variables: HashMap::default(),
15516                                    context_range,
15517                                })
15518                                .templates
15519                                .push((kind, task.original_task().clone()));
15520                        }
15521
15522                        acc
15523                    })
15524            }) else {
15525                return;
15526            };
15527
15528            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15529                buffer.language_settings(cx).tasks.prefer_lsp
15530            }) else {
15531                return;
15532            };
15533
15534            let rows = Self::runnable_rows(
15535                project,
15536                display_snapshot,
15537                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15538                new_rows,
15539                cx.clone(),
15540            )
15541            .await;
15542            editor
15543                .update(cx, |editor, _| {
15544                    editor.clear_tasks();
15545                    for (key, mut value) in rows {
15546                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15547                            value.templates.extend(lsp_tasks.templates);
15548                        }
15549
15550                        editor.insert_tasks(key, value);
15551                    }
15552                    for (key, value) in lsp_tasks_by_rows {
15553                        editor.insert_tasks(key, value);
15554                    }
15555                })
15556                .ok();
15557        })
15558    }
15559    fn fetch_runnable_ranges(
15560        snapshot: &DisplaySnapshot,
15561        range: Range<Anchor>,
15562    ) -> Vec<language::RunnableRange> {
15563        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15564    }
15565
15566    fn runnable_rows(
15567        project: Entity<Project>,
15568        snapshot: DisplaySnapshot,
15569        prefer_lsp: bool,
15570        runnable_ranges: Vec<RunnableRange>,
15571        cx: AsyncWindowContext,
15572    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15573        cx.spawn(async move |cx| {
15574            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15575            for mut runnable in runnable_ranges {
15576                let Some(tasks) = cx
15577                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15578                    .ok()
15579                else {
15580                    continue;
15581                };
15582                let mut tasks = tasks.await;
15583
15584                if prefer_lsp {
15585                    tasks.retain(|(task_kind, _)| {
15586                        !matches!(task_kind, TaskSourceKind::Language { .. })
15587                    });
15588                }
15589                if tasks.is_empty() {
15590                    continue;
15591                }
15592
15593                let point = runnable
15594                    .run_range
15595                    .start
15596                    .to_point(&snapshot.buffer_snapshot());
15597                let Some(row) = snapshot
15598                    .buffer_snapshot()
15599                    .buffer_line_for_row(MultiBufferRow(point.row))
15600                    .map(|(_, range)| range.start.row)
15601                else {
15602                    continue;
15603                };
15604
15605                let context_range =
15606                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15607                runnable_rows.push((
15608                    (runnable.buffer_id, row),
15609                    RunnableTasks {
15610                        templates: tasks,
15611                        offset: snapshot
15612                            .buffer_snapshot()
15613                            .anchor_before(runnable.run_range.start),
15614                        context_range,
15615                        column: point.column,
15616                        extra_variables: runnable.extra_captures,
15617                    },
15618                ));
15619            }
15620            runnable_rows
15621        })
15622    }
15623
15624    fn templates_with_tags(
15625        project: &Entity<Project>,
15626        runnable: &mut Runnable,
15627        cx: &mut App,
15628    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15629        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15630            let (worktree_id, file) = project
15631                .buffer_for_id(runnable.buffer, cx)
15632                .and_then(|buffer| buffer.read(cx).file())
15633                .map(|file| (file.worktree_id(cx), file.clone()))
15634                .unzip();
15635
15636            (
15637                project.task_store().read(cx).task_inventory().cloned(),
15638                worktree_id,
15639                file,
15640            )
15641        });
15642
15643        let tags = mem::take(&mut runnable.tags);
15644        let language = runnable.language.clone();
15645        cx.spawn(async move |cx| {
15646            let mut templates_with_tags = Vec::new();
15647            if let Some(inventory) = inventory {
15648                for RunnableTag(tag) in tags {
15649                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15650                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15651                    }) else {
15652                        return templates_with_tags;
15653                    };
15654                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15655                        move |(_, template)| {
15656                            template.tags.iter().any(|source_tag| source_tag == &tag)
15657                        },
15658                    ));
15659                }
15660            }
15661            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15662
15663            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15664                // Strongest source wins; if we have worktree tag binding, prefer that to
15665                // global and language bindings;
15666                // if we have a global binding, prefer that to language binding.
15667                let first_mismatch = templates_with_tags
15668                    .iter()
15669                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15670                if let Some(index) = first_mismatch {
15671                    templates_with_tags.truncate(index);
15672                }
15673            }
15674
15675            templates_with_tags
15676        })
15677    }
15678
15679    pub fn move_to_enclosing_bracket(
15680        &mut self,
15681        _: &MoveToEnclosingBracket,
15682        window: &mut Window,
15683        cx: &mut Context<Self>,
15684    ) {
15685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15686        self.change_selections(Default::default(), window, cx, |s| {
15687            s.move_offsets_with(|snapshot, selection| {
15688                let Some(enclosing_bracket_ranges) =
15689                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15690                else {
15691                    return;
15692                };
15693
15694                let mut best_length = usize::MAX;
15695                let mut best_inside = false;
15696                let mut best_in_bracket_range = false;
15697                let mut best_destination = None;
15698                for (open, close) in enclosing_bracket_ranges {
15699                    let close = close.to_inclusive();
15700                    let length = close.end() - open.start;
15701                    let inside = selection.start >= open.end && selection.end <= *close.start();
15702                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15703                        || close.contains(&selection.head());
15704
15705                    // If best is next to a bracket and current isn't, skip
15706                    if !in_bracket_range && best_in_bracket_range {
15707                        continue;
15708                    }
15709
15710                    // Prefer smaller lengths unless best is inside and current isn't
15711                    if length > best_length && (best_inside || !inside) {
15712                        continue;
15713                    }
15714
15715                    best_length = length;
15716                    best_inside = inside;
15717                    best_in_bracket_range = in_bracket_range;
15718                    best_destination = Some(
15719                        if close.contains(&selection.start) && close.contains(&selection.end) {
15720                            if inside { open.end } else { open.start }
15721                        } else if inside {
15722                            *close.start()
15723                        } else {
15724                            *close.end()
15725                        },
15726                    );
15727                }
15728
15729                if let Some(destination) = best_destination {
15730                    selection.collapse_to(destination, SelectionGoal::None);
15731                }
15732            })
15733        });
15734    }
15735
15736    pub fn undo_selection(
15737        &mut self,
15738        _: &UndoSelection,
15739        window: &mut Window,
15740        cx: &mut Context<Self>,
15741    ) {
15742        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15743        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15744            self.selection_history.mode = SelectionHistoryMode::Undoing;
15745            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15746                this.end_selection(window, cx);
15747                this.change_selections(
15748                    SelectionEffects::scroll(Autoscroll::newest()),
15749                    window,
15750                    cx,
15751                    |s| s.select_anchors(entry.selections.to_vec()),
15752                );
15753            });
15754            self.selection_history.mode = SelectionHistoryMode::Normal;
15755
15756            self.select_next_state = entry.select_next_state;
15757            self.select_prev_state = entry.select_prev_state;
15758            self.add_selections_state = entry.add_selections_state;
15759        }
15760    }
15761
15762    pub fn redo_selection(
15763        &mut self,
15764        _: &RedoSelection,
15765        window: &mut Window,
15766        cx: &mut Context<Self>,
15767    ) {
15768        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15769        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15770            self.selection_history.mode = SelectionHistoryMode::Redoing;
15771            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15772                this.end_selection(window, cx);
15773                this.change_selections(
15774                    SelectionEffects::scroll(Autoscroll::newest()),
15775                    window,
15776                    cx,
15777                    |s| s.select_anchors(entry.selections.to_vec()),
15778                );
15779            });
15780            self.selection_history.mode = SelectionHistoryMode::Normal;
15781
15782            self.select_next_state = entry.select_next_state;
15783            self.select_prev_state = entry.select_prev_state;
15784            self.add_selections_state = entry.add_selections_state;
15785        }
15786    }
15787
15788    pub fn expand_excerpts(
15789        &mut self,
15790        action: &ExpandExcerpts,
15791        _: &mut Window,
15792        cx: &mut Context<Self>,
15793    ) {
15794        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15795    }
15796
15797    pub fn expand_excerpts_down(
15798        &mut self,
15799        action: &ExpandExcerptsDown,
15800        _: &mut Window,
15801        cx: &mut Context<Self>,
15802    ) {
15803        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15804    }
15805
15806    pub fn expand_excerpts_up(
15807        &mut self,
15808        action: &ExpandExcerptsUp,
15809        _: &mut Window,
15810        cx: &mut Context<Self>,
15811    ) {
15812        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15813    }
15814
15815    pub fn expand_excerpts_for_direction(
15816        &mut self,
15817        lines: u32,
15818        direction: ExpandExcerptDirection,
15819
15820        cx: &mut Context<Self>,
15821    ) {
15822        let selections = self.selections.disjoint_anchors_arc();
15823
15824        let lines = if lines == 0 {
15825            EditorSettings::get_global(cx).expand_excerpt_lines
15826        } else {
15827            lines
15828        };
15829
15830        self.buffer.update(cx, |buffer, cx| {
15831            let snapshot = buffer.snapshot(cx);
15832            let mut excerpt_ids = selections
15833                .iter()
15834                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15835                .collect::<Vec<_>>();
15836            excerpt_ids.sort();
15837            excerpt_ids.dedup();
15838            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15839        })
15840    }
15841
15842    pub fn expand_excerpt(
15843        &mut self,
15844        excerpt: ExcerptId,
15845        direction: ExpandExcerptDirection,
15846        window: &mut Window,
15847        cx: &mut Context<Self>,
15848    ) {
15849        let current_scroll_position = self.scroll_position(cx);
15850        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15851        let mut should_scroll_up = false;
15852
15853        if direction == ExpandExcerptDirection::Down {
15854            let multi_buffer = self.buffer.read(cx);
15855            let snapshot = multi_buffer.snapshot(cx);
15856            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15857                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15858                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15859            {
15860                let buffer_snapshot = buffer.read(cx).snapshot();
15861                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15862                let last_row = buffer_snapshot.max_point().row;
15863                let lines_below = last_row.saturating_sub(excerpt_end_row);
15864                should_scroll_up = lines_below >= lines_to_expand;
15865            }
15866        }
15867
15868        self.buffer.update(cx, |buffer, cx| {
15869            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15870        });
15871
15872        if should_scroll_up {
15873            let new_scroll_position =
15874                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15875            self.set_scroll_position(new_scroll_position, window, cx);
15876        }
15877    }
15878
15879    pub fn go_to_singleton_buffer_point(
15880        &mut self,
15881        point: Point,
15882        window: &mut Window,
15883        cx: &mut Context<Self>,
15884    ) {
15885        self.go_to_singleton_buffer_range(point..point, window, cx);
15886    }
15887
15888    pub fn go_to_singleton_buffer_range(
15889        &mut self,
15890        range: Range<Point>,
15891        window: &mut Window,
15892        cx: &mut Context<Self>,
15893    ) {
15894        let multibuffer = self.buffer().read(cx);
15895        let Some(buffer) = multibuffer.as_singleton() else {
15896            return;
15897        };
15898        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15899            return;
15900        };
15901        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15902            return;
15903        };
15904        self.change_selections(
15905            SelectionEffects::default().nav_history(true),
15906            window,
15907            cx,
15908            |s| s.select_anchor_ranges([start..end]),
15909        );
15910    }
15911
15912    pub fn go_to_diagnostic(
15913        &mut self,
15914        action: &GoToDiagnostic,
15915        window: &mut Window,
15916        cx: &mut Context<Self>,
15917    ) {
15918        if !self.diagnostics_enabled() {
15919            return;
15920        }
15921        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15922        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15923    }
15924
15925    pub fn go_to_prev_diagnostic(
15926        &mut self,
15927        action: &GoToPreviousDiagnostic,
15928        window: &mut Window,
15929        cx: &mut Context<Self>,
15930    ) {
15931        if !self.diagnostics_enabled() {
15932            return;
15933        }
15934        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15935        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15936    }
15937
15938    pub fn go_to_diagnostic_impl(
15939        &mut self,
15940        direction: Direction,
15941        severity: GoToDiagnosticSeverityFilter,
15942        window: &mut Window,
15943        cx: &mut Context<Self>,
15944    ) {
15945        let buffer = self.buffer.read(cx).snapshot(cx);
15946        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
15947
15948        let mut active_group_id = None;
15949        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15950            && active_group.active_range.start.to_offset(&buffer) == selection.start
15951        {
15952            active_group_id = Some(active_group.group_id);
15953        }
15954
15955        fn filtered<'a>(
15956            snapshot: EditorSnapshot,
15957            severity: GoToDiagnosticSeverityFilter,
15958            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
15959        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
15960            diagnostics
15961                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15962                .filter(|entry| entry.range.start != entry.range.end)
15963                .filter(|entry| !entry.diagnostic.is_unnecessary)
15964                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15965        }
15966
15967        let snapshot = self.snapshot(window, cx);
15968        let before = filtered(
15969            snapshot.clone(),
15970            severity,
15971            buffer
15972                .diagnostics_in_range(0..selection.start)
15973                .filter(|entry| entry.range.start <= selection.start),
15974        );
15975        let after = filtered(
15976            snapshot,
15977            severity,
15978            buffer
15979                .diagnostics_in_range(selection.start..buffer.len())
15980                .filter(|entry| entry.range.start >= selection.start),
15981        );
15982
15983        let mut found: Option<DiagnosticEntryRef<usize>> = None;
15984        if direction == Direction::Prev {
15985            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15986            {
15987                for diagnostic in prev_diagnostics.into_iter().rev() {
15988                    if diagnostic.range.start != selection.start
15989                        || active_group_id
15990                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15991                    {
15992                        found = Some(diagnostic);
15993                        break 'outer;
15994                    }
15995                }
15996            }
15997        } else {
15998            for diagnostic in after.chain(before) {
15999                if diagnostic.range.start != selection.start
16000                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16001                {
16002                    found = Some(diagnostic);
16003                    break;
16004                }
16005            }
16006        }
16007        let Some(next_diagnostic) = found else {
16008            return;
16009        };
16010
16011        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16012        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16013            return;
16014        };
16015        self.change_selections(Default::default(), window, cx, |s| {
16016            s.select_ranges(vec![
16017                next_diagnostic.range.start..next_diagnostic.range.start,
16018            ])
16019        });
16020        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16021        self.refresh_edit_prediction(false, true, window, cx);
16022    }
16023
16024    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16025        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16026        let snapshot = self.snapshot(window, cx);
16027        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16028        self.go_to_hunk_before_or_after_position(
16029            &snapshot,
16030            selection.head(),
16031            Direction::Next,
16032            window,
16033            cx,
16034        );
16035    }
16036
16037    pub fn go_to_hunk_before_or_after_position(
16038        &mut self,
16039        snapshot: &EditorSnapshot,
16040        position: Point,
16041        direction: Direction,
16042        window: &mut Window,
16043        cx: &mut Context<Editor>,
16044    ) {
16045        let row = if direction == Direction::Next {
16046            self.hunk_after_position(snapshot, position)
16047                .map(|hunk| hunk.row_range.start)
16048        } else {
16049            self.hunk_before_position(snapshot, position)
16050        };
16051
16052        if let Some(row) = row {
16053            let destination = Point::new(row.0, 0);
16054            let autoscroll = Autoscroll::center();
16055
16056            self.unfold_ranges(&[destination..destination], false, false, cx);
16057            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16058                s.select_ranges([destination..destination]);
16059            });
16060        }
16061    }
16062
16063    fn hunk_after_position(
16064        &mut self,
16065        snapshot: &EditorSnapshot,
16066        position: Point,
16067    ) -> Option<MultiBufferDiffHunk> {
16068        snapshot
16069            .buffer_snapshot()
16070            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16071            .find(|hunk| hunk.row_range.start.0 > position.row)
16072            .or_else(|| {
16073                snapshot
16074                    .buffer_snapshot()
16075                    .diff_hunks_in_range(Point::zero()..position)
16076                    .find(|hunk| hunk.row_range.end.0 < position.row)
16077            })
16078    }
16079
16080    fn go_to_prev_hunk(
16081        &mut self,
16082        _: &GoToPreviousHunk,
16083        window: &mut Window,
16084        cx: &mut Context<Self>,
16085    ) {
16086        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16087        let snapshot = self.snapshot(window, cx);
16088        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16089        self.go_to_hunk_before_or_after_position(
16090            &snapshot,
16091            selection.head(),
16092            Direction::Prev,
16093            window,
16094            cx,
16095        );
16096    }
16097
16098    fn hunk_before_position(
16099        &mut self,
16100        snapshot: &EditorSnapshot,
16101        position: Point,
16102    ) -> Option<MultiBufferRow> {
16103        snapshot
16104            .buffer_snapshot()
16105            .diff_hunk_before(position)
16106            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16107    }
16108
16109    fn go_to_next_change(
16110        &mut self,
16111        _: &GoToNextChange,
16112        window: &mut Window,
16113        cx: &mut Context<Self>,
16114    ) {
16115        if let Some(selections) = self
16116            .change_list
16117            .next_change(1, Direction::Next)
16118            .map(|s| s.to_vec())
16119        {
16120            self.change_selections(Default::default(), window, cx, |s| {
16121                let map = s.display_map();
16122                s.select_display_ranges(selections.iter().map(|a| {
16123                    let point = a.to_display_point(&map);
16124                    point..point
16125                }))
16126            })
16127        }
16128    }
16129
16130    fn go_to_previous_change(
16131        &mut self,
16132        _: &GoToPreviousChange,
16133        window: &mut Window,
16134        cx: &mut Context<Self>,
16135    ) {
16136        if let Some(selections) = self
16137            .change_list
16138            .next_change(1, Direction::Prev)
16139            .map(|s| s.to_vec())
16140        {
16141            self.change_selections(Default::default(), window, cx, |s| {
16142                let map = s.display_map();
16143                s.select_display_ranges(selections.iter().map(|a| {
16144                    let point = a.to_display_point(&map);
16145                    point..point
16146                }))
16147            })
16148        }
16149    }
16150
16151    pub fn go_to_next_document_highlight(
16152        &mut self,
16153        _: &GoToNextDocumentHighlight,
16154        window: &mut Window,
16155        cx: &mut Context<Self>,
16156    ) {
16157        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16158    }
16159
16160    pub fn go_to_prev_document_highlight(
16161        &mut self,
16162        _: &GoToPreviousDocumentHighlight,
16163        window: &mut Window,
16164        cx: &mut Context<Self>,
16165    ) {
16166        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16167    }
16168
16169    pub fn go_to_document_highlight_before_or_after_position(
16170        &mut self,
16171        direction: Direction,
16172        window: &mut Window,
16173        cx: &mut Context<Editor>,
16174    ) {
16175        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16176        let snapshot = self.snapshot(window, cx);
16177        let buffer = &snapshot.buffer_snapshot();
16178        let position = self
16179            .selections
16180            .newest::<Point>(&snapshot.display_snapshot)
16181            .head();
16182        let anchor_position = buffer.anchor_after(position);
16183
16184        // Get all document highlights (both read and write)
16185        let mut all_highlights = Vec::new();
16186
16187        if let Some((_, read_highlights)) = self
16188            .background_highlights
16189            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16190        {
16191            all_highlights.extend(read_highlights.iter());
16192        }
16193
16194        if let Some((_, write_highlights)) = self
16195            .background_highlights
16196            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16197        {
16198            all_highlights.extend(write_highlights.iter());
16199        }
16200
16201        if all_highlights.is_empty() {
16202            return;
16203        }
16204
16205        // Sort highlights by position
16206        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16207
16208        let target_highlight = match direction {
16209            Direction::Next => {
16210                // Find the first highlight after the current position
16211                all_highlights
16212                    .iter()
16213                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16214            }
16215            Direction::Prev => {
16216                // Find the last highlight before the current position
16217                all_highlights
16218                    .iter()
16219                    .rev()
16220                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16221            }
16222        };
16223
16224        if let Some(highlight) = target_highlight {
16225            let destination = highlight.start.to_point(buffer);
16226            let autoscroll = Autoscroll::center();
16227
16228            self.unfold_ranges(&[destination..destination], false, false, cx);
16229            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16230                s.select_ranges([destination..destination]);
16231            });
16232        }
16233    }
16234
16235    fn go_to_line<T: 'static>(
16236        &mut self,
16237        position: Anchor,
16238        highlight_color: Option<Hsla>,
16239        window: &mut Window,
16240        cx: &mut Context<Self>,
16241    ) {
16242        let snapshot = self.snapshot(window, cx).display_snapshot;
16243        let position = position.to_point(&snapshot.buffer_snapshot());
16244        let start = snapshot
16245            .buffer_snapshot()
16246            .clip_point(Point::new(position.row, 0), Bias::Left);
16247        let end = start + Point::new(1, 0);
16248        let start = snapshot.buffer_snapshot().anchor_before(start);
16249        let end = snapshot.buffer_snapshot().anchor_before(end);
16250
16251        self.highlight_rows::<T>(
16252            start..end,
16253            highlight_color
16254                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16255            Default::default(),
16256            cx,
16257        );
16258
16259        if self.buffer.read(cx).is_singleton() {
16260            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16261        }
16262    }
16263
16264    pub fn go_to_definition(
16265        &mut self,
16266        _: &GoToDefinition,
16267        window: &mut Window,
16268        cx: &mut Context<Self>,
16269    ) -> Task<Result<Navigated>> {
16270        let definition =
16271            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16272        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16273        cx.spawn_in(window, async move |editor, cx| {
16274            if definition.await? == Navigated::Yes {
16275                return Ok(Navigated::Yes);
16276            }
16277            match fallback_strategy {
16278                GoToDefinitionFallback::None => Ok(Navigated::No),
16279                GoToDefinitionFallback::FindAllReferences => {
16280                    match editor.update_in(cx, |editor, window, cx| {
16281                        editor.find_all_references(&FindAllReferences, window, cx)
16282                    })? {
16283                        Some(references) => references.await,
16284                        None => Ok(Navigated::No),
16285                    }
16286                }
16287            }
16288        })
16289    }
16290
16291    pub fn go_to_declaration(
16292        &mut self,
16293        _: &GoToDeclaration,
16294        window: &mut Window,
16295        cx: &mut Context<Self>,
16296    ) -> Task<Result<Navigated>> {
16297        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16298    }
16299
16300    pub fn go_to_declaration_split(
16301        &mut self,
16302        _: &GoToDeclaration,
16303        window: &mut Window,
16304        cx: &mut Context<Self>,
16305    ) -> Task<Result<Navigated>> {
16306        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16307    }
16308
16309    pub fn go_to_implementation(
16310        &mut self,
16311        _: &GoToImplementation,
16312        window: &mut Window,
16313        cx: &mut Context<Self>,
16314    ) -> Task<Result<Navigated>> {
16315        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16316    }
16317
16318    pub fn go_to_implementation_split(
16319        &mut self,
16320        _: &GoToImplementationSplit,
16321        window: &mut Window,
16322        cx: &mut Context<Self>,
16323    ) -> Task<Result<Navigated>> {
16324        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16325    }
16326
16327    pub fn go_to_type_definition(
16328        &mut self,
16329        _: &GoToTypeDefinition,
16330        window: &mut Window,
16331        cx: &mut Context<Self>,
16332    ) -> Task<Result<Navigated>> {
16333        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16334    }
16335
16336    pub fn go_to_definition_split(
16337        &mut self,
16338        _: &GoToDefinitionSplit,
16339        window: &mut Window,
16340        cx: &mut Context<Self>,
16341    ) -> Task<Result<Navigated>> {
16342        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16343    }
16344
16345    pub fn go_to_type_definition_split(
16346        &mut self,
16347        _: &GoToTypeDefinitionSplit,
16348        window: &mut Window,
16349        cx: &mut Context<Self>,
16350    ) -> Task<Result<Navigated>> {
16351        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16352    }
16353
16354    fn go_to_definition_of_kind(
16355        &mut self,
16356        kind: GotoDefinitionKind,
16357        split: bool,
16358        window: &mut Window,
16359        cx: &mut Context<Self>,
16360    ) -> Task<Result<Navigated>> {
16361        let Some(provider) = self.semantics_provider.clone() else {
16362            return Task::ready(Ok(Navigated::No));
16363        };
16364        let head = self
16365            .selections
16366            .newest::<usize>(&self.display_snapshot(cx))
16367            .head();
16368        let buffer = self.buffer.read(cx);
16369        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16370            return Task::ready(Ok(Navigated::No));
16371        };
16372        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16373            return Task::ready(Ok(Navigated::No));
16374        };
16375
16376        cx.spawn_in(window, async move |editor, cx| {
16377            let Some(definitions) = definitions.await? else {
16378                return Ok(Navigated::No);
16379            };
16380            let navigated = editor
16381                .update_in(cx, |editor, window, cx| {
16382                    editor.navigate_to_hover_links(
16383                        Some(kind),
16384                        definitions
16385                            .into_iter()
16386                            .filter(|location| {
16387                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16388                            })
16389                            .map(HoverLink::Text)
16390                            .collect::<Vec<_>>(),
16391                        split,
16392                        window,
16393                        cx,
16394                    )
16395                })?
16396                .await?;
16397            anyhow::Ok(navigated)
16398        })
16399    }
16400
16401    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16402        let selection = self.selections.newest_anchor();
16403        let head = selection.head();
16404        let tail = selection.tail();
16405
16406        let Some((buffer, start_position)) =
16407            self.buffer.read(cx).text_anchor_for_position(head, cx)
16408        else {
16409            return;
16410        };
16411
16412        let end_position = if head != tail {
16413            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16414                return;
16415            };
16416            Some(pos)
16417        } else {
16418            None
16419        };
16420
16421        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16422            let url = if let Some(end_pos) = end_position {
16423                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16424            } else {
16425                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16426            };
16427
16428            if let Some(url) = url {
16429                cx.update(|window, cx| {
16430                    if parse_zed_link(&url, cx).is_some() {
16431                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16432                    } else {
16433                        cx.open_url(&url);
16434                    }
16435                })?;
16436            }
16437
16438            anyhow::Ok(())
16439        });
16440
16441        url_finder.detach();
16442    }
16443
16444    pub fn open_selected_filename(
16445        &mut self,
16446        _: &OpenSelectedFilename,
16447        window: &mut Window,
16448        cx: &mut Context<Self>,
16449    ) {
16450        let Some(workspace) = self.workspace() else {
16451            return;
16452        };
16453
16454        let position = self.selections.newest_anchor().head();
16455
16456        let Some((buffer, buffer_position)) =
16457            self.buffer.read(cx).text_anchor_for_position(position, cx)
16458        else {
16459            return;
16460        };
16461
16462        let project = self.project.clone();
16463
16464        cx.spawn_in(window, async move |_, cx| {
16465            let result = find_file(&buffer, project, buffer_position, cx).await;
16466
16467            if let Some((_, path)) = result {
16468                workspace
16469                    .update_in(cx, |workspace, window, cx| {
16470                        workspace.open_resolved_path(path, window, cx)
16471                    })?
16472                    .await?;
16473            }
16474            anyhow::Ok(())
16475        })
16476        .detach();
16477    }
16478
16479    pub(crate) fn navigate_to_hover_links(
16480        &mut self,
16481        kind: Option<GotoDefinitionKind>,
16482        definitions: Vec<HoverLink>,
16483        split: bool,
16484        window: &mut Window,
16485        cx: &mut Context<Editor>,
16486    ) -> Task<Result<Navigated>> {
16487        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16488        let mut first_url_or_file = None;
16489        let definitions: Vec<_> = definitions
16490            .into_iter()
16491            .filter_map(|def| match def {
16492                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16493                HoverLink::InlayHint(lsp_location, server_id) => {
16494                    let computation =
16495                        self.compute_target_location(lsp_location, server_id, window, cx);
16496                    Some(cx.background_spawn(computation))
16497                }
16498                HoverLink::Url(url) => {
16499                    first_url_or_file = Some(Either::Left(url));
16500                    None
16501                }
16502                HoverLink::File(path) => {
16503                    first_url_or_file = Some(Either::Right(path));
16504                    None
16505                }
16506            })
16507            .collect();
16508
16509        let workspace = self.workspace();
16510
16511        cx.spawn_in(window, async move |editor, cx| {
16512            let locations: Vec<Location> = future::join_all(definitions)
16513                .await
16514                .into_iter()
16515                .filter_map(|location| location.transpose())
16516                .collect::<Result<_>>()
16517                .context("location tasks")?;
16518            let mut locations = cx.update(|_, cx| {
16519                locations
16520                    .into_iter()
16521                    .map(|location| {
16522                        let buffer = location.buffer.read(cx);
16523                        (location.buffer, location.range.to_point(buffer))
16524                    })
16525                    .into_group_map()
16526            })?;
16527            let mut num_locations = 0;
16528            for ranges in locations.values_mut() {
16529                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16530                ranges.dedup();
16531                num_locations += ranges.len();
16532            }
16533
16534            if num_locations > 1 {
16535                let Some(workspace) = workspace else {
16536                    return Ok(Navigated::No);
16537                };
16538
16539                let tab_kind = match kind {
16540                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16541                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16542                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16543                    Some(GotoDefinitionKind::Type) => "Types",
16544                };
16545                let title = editor
16546                    .update_in(cx, |_, _, cx| {
16547                        let target = locations
16548                            .iter()
16549                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16550                            .map(|(buffer, location)| {
16551                                buffer
16552                                    .read(cx)
16553                                    .text_for_range(location.clone())
16554                                    .collect::<String>()
16555                            })
16556                            .filter(|text| !text.contains('\n'))
16557                            .unique()
16558                            .take(3)
16559                            .join(", ");
16560                        if target.is_empty() {
16561                            tab_kind.to_owned()
16562                        } else {
16563                            format!("{tab_kind} for {target}")
16564                        }
16565                    })
16566                    .context("buffer title")?;
16567
16568                let opened = workspace
16569                    .update_in(cx, |workspace, window, cx| {
16570                        Self::open_locations_in_multibuffer(
16571                            workspace,
16572                            locations,
16573                            title,
16574                            split,
16575                            MultibufferSelectionMode::First,
16576                            window,
16577                            cx,
16578                        )
16579                    })
16580                    .is_ok();
16581
16582                anyhow::Ok(Navigated::from_bool(opened))
16583            } else if num_locations == 0 {
16584                // If there is one url or file, open it directly
16585                match first_url_or_file {
16586                    Some(Either::Left(url)) => {
16587                        cx.update(|_, cx| cx.open_url(&url))?;
16588                        Ok(Navigated::Yes)
16589                    }
16590                    Some(Either::Right(path)) => {
16591                        let Some(workspace) = workspace else {
16592                            return Ok(Navigated::No);
16593                        };
16594
16595                        workspace
16596                            .update_in(cx, |workspace, window, cx| {
16597                                workspace.open_resolved_path(path, window, cx)
16598                            })?
16599                            .await?;
16600                        Ok(Navigated::Yes)
16601                    }
16602                    None => Ok(Navigated::No),
16603                }
16604            } else {
16605                let Some(workspace) = workspace else {
16606                    return Ok(Navigated::No);
16607                };
16608
16609                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16610                let target_range = target_ranges.first().unwrap().clone();
16611
16612                editor.update_in(cx, |editor, window, cx| {
16613                    let range = target_range.to_point(target_buffer.read(cx));
16614                    let range = editor.range_for_match(&range);
16615                    let range = collapse_multiline_range(range);
16616
16617                    if !split
16618                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16619                    {
16620                        editor.go_to_singleton_buffer_range(range, window, cx);
16621                    } else {
16622                        let pane = workspace.read(cx).active_pane().clone();
16623                        window.defer(cx, move |window, cx| {
16624                            let target_editor: Entity<Self> =
16625                                workspace.update(cx, |workspace, cx| {
16626                                    let pane = if split {
16627                                        workspace.adjacent_pane(window, cx)
16628                                    } else {
16629                                        workspace.active_pane().clone()
16630                                    };
16631
16632                                    workspace.open_project_item(
16633                                        pane,
16634                                        target_buffer.clone(),
16635                                        true,
16636                                        true,
16637                                        window,
16638                                        cx,
16639                                    )
16640                                });
16641                            target_editor.update(cx, |target_editor, cx| {
16642                                // When selecting a definition in a different buffer, disable the nav history
16643                                // to avoid creating a history entry at the previous cursor location.
16644                                pane.update(cx, |pane, _| pane.disable_history());
16645                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16646                                pane.update(cx, |pane, _| pane.enable_history());
16647                            });
16648                        });
16649                    }
16650                    Navigated::Yes
16651                })
16652            }
16653        })
16654    }
16655
16656    fn compute_target_location(
16657        &self,
16658        lsp_location: lsp::Location,
16659        server_id: LanguageServerId,
16660        window: &mut Window,
16661        cx: &mut Context<Self>,
16662    ) -> Task<anyhow::Result<Option<Location>>> {
16663        let Some(project) = self.project.clone() else {
16664            return Task::ready(Ok(None));
16665        };
16666
16667        cx.spawn_in(window, async move |editor, cx| {
16668            let location_task = editor.update(cx, |_, cx| {
16669                project.update(cx, |project, cx| {
16670                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16671                })
16672            })?;
16673            let location = Some({
16674                let target_buffer_handle = location_task.await.context("open local buffer")?;
16675                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16676                    let target_start = target_buffer
16677                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16678                    let target_end = target_buffer
16679                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16680                    target_buffer.anchor_after(target_start)
16681                        ..target_buffer.anchor_before(target_end)
16682                })?;
16683                Location {
16684                    buffer: target_buffer_handle,
16685                    range,
16686                }
16687            });
16688            Ok(location)
16689        })
16690    }
16691
16692    fn go_to_next_reference(
16693        &mut self,
16694        _: &GoToNextReference,
16695        window: &mut Window,
16696        cx: &mut Context<Self>,
16697    ) {
16698        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16699        if let Some(task) = task {
16700            task.detach();
16701        };
16702    }
16703
16704    fn go_to_prev_reference(
16705        &mut self,
16706        _: &GoToPreviousReference,
16707        window: &mut Window,
16708        cx: &mut Context<Self>,
16709    ) {
16710        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16711        if let Some(task) = task {
16712            task.detach();
16713        };
16714    }
16715
16716    pub fn go_to_reference_before_or_after_position(
16717        &mut self,
16718        direction: Direction,
16719        count: usize,
16720        window: &mut Window,
16721        cx: &mut Context<Self>,
16722    ) -> Option<Task<Result<()>>> {
16723        let selection = self.selections.newest_anchor();
16724        let head = selection.head();
16725
16726        let multi_buffer = self.buffer.read(cx);
16727
16728        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16729        let workspace = self.workspace()?;
16730        let project = workspace.read(cx).project().clone();
16731        let references =
16732            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16733        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16734            let Some(locations) = references.await? else {
16735                return Ok(());
16736            };
16737
16738            if locations.is_empty() {
16739                // totally normal - the cursor may be on something which is not
16740                // a symbol (e.g. a keyword)
16741                log::info!("no references found under cursor");
16742                return Ok(());
16743            }
16744
16745            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16746
16747            let multi_buffer_snapshot =
16748                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16749
16750            let (locations, current_location_index) =
16751                multi_buffer.update(cx, |multi_buffer, cx| {
16752                    let mut locations = locations
16753                        .into_iter()
16754                        .filter_map(|loc| {
16755                            let start = multi_buffer.buffer_anchor_to_anchor(
16756                                &loc.buffer,
16757                                loc.range.start,
16758                                cx,
16759                            )?;
16760                            let end = multi_buffer.buffer_anchor_to_anchor(
16761                                &loc.buffer,
16762                                loc.range.end,
16763                                cx,
16764                            )?;
16765                            Some(start..end)
16766                        })
16767                        .collect::<Vec<_>>();
16768
16769                    // There is an O(n) implementation, but given this list will be
16770                    // small (usually <100 items), the extra O(log(n)) factor isn't
16771                    // worth the (surprisingly large amount of) extra complexity.
16772                    locations
16773                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16774
16775                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16776
16777                    let current_location_index = locations.iter().position(|loc| {
16778                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16779                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16780                    });
16781
16782                    (locations, current_location_index)
16783                })?;
16784
16785            let Some(current_location_index) = current_location_index else {
16786                // This indicates something has gone wrong, because we already
16787                // handle the "no references" case above
16788                log::error!(
16789                    "failed to find current reference under cursor. Total references: {}",
16790                    locations.len()
16791                );
16792                return Ok(());
16793            };
16794
16795            let destination_location_index = match direction {
16796                Direction::Next => (current_location_index + count) % locations.len(),
16797                Direction::Prev => {
16798                    (current_location_index + locations.len() - count % locations.len())
16799                        % locations.len()
16800                }
16801            };
16802
16803            // TODO(cameron): is this needed?
16804            // the thinking is to avoid "jumping to the current location" (avoid
16805            // polluting "jumplist" in vim terms)
16806            if current_location_index == destination_location_index {
16807                return Ok(());
16808            }
16809
16810            let Range { start, end } = locations[destination_location_index];
16811
16812            editor.update_in(cx, |editor, window, cx| {
16813                let effects = SelectionEffects::default();
16814
16815                editor.unfold_ranges(&[start..end], false, false, cx);
16816                editor.change_selections(effects, window, cx, |s| {
16817                    s.select_ranges([start..start]);
16818                });
16819            })?;
16820
16821            Ok(())
16822        }))
16823    }
16824
16825    pub fn find_all_references(
16826        &mut self,
16827        _: &FindAllReferences,
16828        window: &mut Window,
16829        cx: &mut Context<Self>,
16830    ) -> Option<Task<Result<Navigated>>> {
16831        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16832        let multi_buffer = self.buffer.read(cx);
16833        let head = selection.head();
16834
16835        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16836        let head_anchor = multi_buffer_snapshot.anchor_at(
16837            head,
16838            if head < selection.tail() {
16839                Bias::Right
16840            } else {
16841                Bias::Left
16842            },
16843        );
16844
16845        match self
16846            .find_all_references_task_sources
16847            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16848        {
16849            Ok(_) => {
16850                log::info!(
16851                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16852                );
16853                return None;
16854            }
16855            Err(i) => {
16856                self.find_all_references_task_sources.insert(i, head_anchor);
16857            }
16858        }
16859
16860        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16861        let workspace = self.workspace()?;
16862        let project = workspace.read(cx).project().clone();
16863        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16864        Some(cx.spawn_in(window, async move |editor, cx| {
16865            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16866                if let Ok(i) = editor
16867                    .find_all_references_task_sources
16868                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16869                {
16870                    editor.find_all_references_task_sources.remove(i);
16871                }
16872            });
16873
16874            let Some(locations) = references.await? else {
16875                return anyhow::Ok(Navigated::No);
16876            };
16877            let mut locations = cx.update(|_, cx| {
16878                locations
16879                    .into_iter()
16880                    .map(|location| {
16881                        let buffer = location.buffer.read(cx);
16882                        (location.buffer, location.range.to_point(buffer))
16883                    })
16884                    .into_group_map()
16885            })?;
16886            if locations.is_empty() {
16887                return anyhow::Ok(Navigated::No);
16888            }
16889            for ranges in locations.values_mut() {
16890                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16891                ranges.dedup();
16892            }
16893
16894            workspace.update_in(cx, |workspace, window, cx| {
16895                let target = locations
16896                    .iter()
16897                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16898                    .map(|(buffer, location)| {
16899                        buffer
16900                            .read(cx)
16901                            .text_for_range(location.clone())
16902                            .collect::<String>()
16903                    })
16904                    .filter(|text| !text.contains('\n'))
16905                    .unique()
16906                    .take(3)
16907                    .join(", ");
16908                let title = if target.is_empty() {
16909                    "References".to_owned()
16910                } else {
16911                    format!("References to {target}")
16912                };
16913                Self::open_locations_in_multibuffer(
16914                    workspace,
16915                    locations,
16916                    title,
16917                    false,
16918                    MultibufferSelectionMode::First,
16919                    window,
16920                    cx,
16921                );
16922                Navigated::Yes
16923            })
16924        }))
16925    }
16926
16927    /// Opens a multibuffer with the given project locations in it
16928    pub fn open_locations_in_multibuffer(
16929        workspace: &mut Workspace,
16930        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16931        title: String,
16932        split: bool,
16933        multibuffer_selection_mode: MultibufferSelectionMode,
16934        window: &mut Window,
16935        cx: &mut Context<Workspace>,
16936    ) {
16937        if locations.is_empty() {
16938            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16939            return;
16940        }
16941
16942        let capability = workspace.project().read(cx).capability();
16943        let mut ranges = <Vec<Range<Anchor>>>::new();
16944
16945        // a key to find existing multibuffer editors with the same set of locations
16946        // to prevent us from opening more and more multibuffer tabs for searches and the like
16947        let mut key = (title.clone(), vec![]);
16948        let excerpt_buffer = cx.new(|cx| {
16949            let key = &mut key.1;
16950            let mut multibuffer = MultiBuffer::new(capability);
16951            for (buffer, mut ranges_for_buffer) in locations {
16952                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16953                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16954                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16955                    PathKey::for_buffer(&buffer, cx),
16956                    buffer.clone(),
16957                    ranges_for_buffer,
16958                    multibuffer_context_lines(cx),
16959                    cx,
16960                );
16961                ranges.extend(new_ranges)
16962            }
16963
16964            multibuffer.with_title(title)
16965        });
16966        let existing = workspace.active_pane().update(cx, |pane, cx| {
16967            pane.items()
16968                .filter_map(|item| item.downcast::<Editor>())
16969                .find(|editor| {
16970                    editor
16971                        .read(cx)
16972                        .lookup_key
16973                        .as_ref()
16974                        .and_then(|it| {
16975                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16976                        })
16977                        .is_some_and(|it| *it == key)
16978                })
16979        });
16980        let editor = existing.unwrap_or_else(|| {
16981            cx.new(|cx| {
16982                let mut editor = Editor::for_multibuffer(
16983                    excerpt_buffer,
16984                    Some(workspace.project().clone()),
16985                    window,
16986                    cx,
16987                );
16988                editor.lookup_key = Some(Box::new(key));
16989                editor
16990            })
16991        });
16992        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
16993            MultibufferSelectionMode::First => {
16994                if let Some(first_range) = ranges.first() {
16995                    editor.change_selections(
16996                        SelectionEffects::no_scroll(),
16997                        window,
16998                        cx,
16999                        |selections| {
17000                            selections.clear_disjoint();
17001                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17002                        },
17003                    );
17004                }
17005                editor.highlight_background::<Self>(
17006                    &ranges,
17007                    |theme| theme.colors().editor_highlighted_line_background,
17008                    cx,
17009                );
17010            }
17011            MultibufferSelectionMode::All => {
17012                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17013                    selections.clear_disjoint();
17014                    selections.select_anchor_ranges(ranges);
17015                });
17016            }
17017        });
17018
17019        let item = Box::new(editor);
17020        let item_id = item.item_id();
17021
17022        if split {
17023            let pane = workspace.adjacent_pane(window, cx);
17024            workspace.add_item(pane, item, None, true, true, window, cx);
17025        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17026            let (preview_item_id, preview_item_idx) =
17027                workspace.active_pane().read_with(cx, |pane, _| {
17028                    (pane.preview_item_id(), pane.preview_item_idx())
17029                });
17030
17031            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17032
17033            if let Some(preview_item_id) = preview_item_id {
17034                workspace.active_pane().update(cx, |pane, cx| {
17035                    pane.remove_item(preview_item_id, false, false, window, cx);
17036                });
17037            }
17038        } else {
17039            workspace.add_item_to_active_pane(item, None, true, window, cx);
17040        }
17041        workspace.active_pane().update(cx, |pane, cx| {
17042            pane.set_preview_item_id(Some(item_id), cx);
17043        });
17044    }
17045
17046    pub fn rename(
17047        &mut self,
17048        _: &Rename,
17049        window: &mut Window,
17050        cx: &mut Context<Self>,
17051    ) -> Option<Task<Result<()>>> {
17052        use language::ToOffset as _;
17053
17054        let provider = self.semantics_provider.clone()?;
17055        let selection = self.selections.newest_anchor().clone();
17056        let (cursor_buffer, cursor_buffer_position) = self
17057            .buffer
17058            .read(cx)
17059            .text_anchor_for_position(selection.head(), cx)?;
17060        let (tail_buffer, cursor_buffer_position_end) = self
17061            .buffer
17062            .read(cx)
17063            .text_anchor_for_position(selection.tail(), cx)?;
17064        if tail_buffer != cursor_buffer {
17065            return None;
17066        }
17067
17068        let snapshot = cursor_buffer.read(cx).snapshot();
17069        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17070        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17071        let prepare_rename = provider
17072            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17073            .unwrap_or_else(|| Task::ready(Ok(None)));
17074        drop(snapshot);
17075
17076        Some(cx.spawn_in(window, async move |this, cx| {
17077            let rename_range = if let Some(range) = prepare_rename.await? {
17078                Some(range)
17079            } else {
17080                this.update(cx, |this, cx| {
17081                    let buffer = this.buffer.read(cx).snapshot(cx);
17082                    let mut buffer_highlights = this
17083                        .document_highlights_for_position(selection.head(), &buffer)
17084                        .filter(|highlight| {
17085                            highlight.start.excerpt_id == selection.head().excerpt_id
17086                                && highlight.end.excerpt_id == selection.head().excerpt_id
17087                        });
17088                    buffer_highlights
17089                        .next()
17090                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17091                })?
17092            };
17093            if let Some(rename_range) = rename_range {
17094                this.update_in(cx, |this, window, cx| {
17095                    let snapshot = cursor_buffer.read(cx).snapshot();
17096                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17097                    let cursor_offset_in_rename_range =
17098                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17099                    let cursor_offset_in_rename_range_end =
17100                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17101
17102                    this.take_rename(false, window, cx);
17103                    let buffer = this.buffer.read(cx).read(cx);
17104                    let cursor_offset = selection.head().to_offset(&buffer);
17105                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17106                    let rename_end = rename_start + rename_buffer_range.len();
17107                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17108                    let mut old_highlight_id = None;
17109                    let old_name: Arc<str> = buffer
17110                        .chunks(rename_start..rename_end, true)
17111                        .map(|chunk| {
17112                            if old_highlight_id.is_none() {
17113                                old_highlight_id = chunk.syntax_highlight_id;
17114                            }
17115                            chunk.text
17116                        })
17117                        .collect::<String>()
17118                        .into();
17119
17120                    drop(buffer);
17121
17122                    // Position the selection in the rename editor so that it matches the current selection.
17123                    this.show_local_selections = false;
17124                    let rename_editor = cx.new(|cx| {
17125                        let mut editor = Editor::single_line(window, cx);
17126                        editor.buffer.update(cx, |buffer, cx| {
17127                            buffer.edit([(0..0, old_name.clone())], None, cx)
17128                        });
17129                        let rename_selection_range = match cursor_offset_in_rename_range
17130                            .cmp(&cursor_offset_in_rename_range_end)
17131                        {
17132                            Ordering::Equal => {
17133                                editor.select_all(&SelectAll, window, cx);
17134                                return editor;
17135                            }
17136                            Ordering::Less => {
17137                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17138                            }
17139                            Ordering::Greater => {
17140                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17141                            }
17142                        };
17143                        if rename_selection_range.end > old_name.len() {
17144                            editor.select_all(&SelectAll, window, cx);
17145                        } else {
17146                            editor.change_selections(Default::default(), window, cx, |s| {
17147                                s.select_ranges([rename_selection_range]);
17148                            });
17149                        }
17150                        editor
17151                    });
17152                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17153                        if e == &EditorEvent::Focused {
17154                            cx.emit(EditorEvent::FocusedIn)
17155                        }
17156                    })
17157                    .detach();
17158
17159                    let write_highlights =
17160                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17161                    let read_highlights =
17162                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17163                    let ranges = write_highlights
17164                        .iter()
17165                        .flat_map(|(_, ranges)| ranges.iter())
17166                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17167                        .cloned()
17168                        .collect();
17169
17170                    this.highlight_text::<Rename>(
17171                        ranges,
17172                        HighlightStyle {
17173                            fade_out: Some(0.6),
17174                            ..Default::default()
17175                        },
17176                        cx,
17177                    );
17178                    let rename_focus_handle = rename_editor.focus_handle(cx);
17179                    window.focus(&rename_focus_handle);
17180                    let block_id = this.insert_blocks(
17181                        [BlockProperties {
17182                            style: BlockStyle::Flex,
17183                            placement: BlockPlacement::Below(range.start),
17184                            height: Some(1),
17185                            render: Arc::new({
17186                                let rename_editor = rename_editor.clone();
17187                                move |cx: &mut BlockContext| {
17188                                    let mut text_style = cx.editor_style.text.clone();
17189                                    if let Some(highlight_style) = old_highlight_id
17190                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17191                                    {
17192                                        text_style = text_style.highlight(highlight_style);
17193                                    }
17194                                    div()
17195                                        .block_mouse_except_scroll()
17196                                        .pl(cx.anchor_x)
17197                                        .child(EditorElement::new(
17198                                            &rename_editor,
17199                                            EditorStyle {
17200                                                background: cx.theme().system().transparent,
17201                                                local_player: cx.editor_style.local_player,
17202                                                text: text_style,
17203                                                scrollbar_width: cx.editor_style.scrollbar_width,
17204                                                syntax: cx.editor_style.syntax.clone(),
17205                                                status: cx.editor_style.status.clone(),
17206                                                inlay_hints_style: HighlightStyle {
17207                                                    font_weight: Some(FontWeight::BOLD),
17208                                                    ..make_inlay_hints_style(cx.app)
17209                                                },
17210                                                edit_prediction_styles: make_suggestion_styles(
17211                                                    cx.app,
17212                                                ),
17213                                                ..EditorStyle::default()
17214                                            },
17215                                        ))
17216                                        .into_any_element()
17217                                }
17218                            }),
17219                            priority: 0,
17220                        }],
17221                        Some(Autoscroll::fit()),
17222                        cx,
17223                    )[0];
17224                    this.pending_rename = Some(RenameState {
17225                        range,
17226                        old_name,
17227                        editor: rename_editor,
17228                        block_id,
17229                    });
17230                })?;
17231            }
17232
17233            Ok(())
17234        }))
17235    }
17236
17237    pub fn confirm_rename(
17238        &mut self,
17239        _: &ConfirmRename,
17240        window: &mut Window,
17241        cx: &mut Context<Self>,
17242    ) -> Option<Task<Result<()>>> {
17243        let rename = self.take_rename(false, window, cx)?;
17244        let workspace = self.workspace()?.downgrade();
17245        let (buffer, start) = self
17246            .buffer
17247            .read(cx)
17248            .text_anchor_for_position(rename.range.start, cx)?;
17249        let (end_buffer, _) = self
17250            .buffer
17251            .read(cx)
17252            .text_anchor_for_position(rename.range.end, cx)?;
17253        if buffer != end_buffer {
17254            return None;
17255        }
17256
17257        let old_name = rename.old_name;
17258        let new_name = rename.editor.read(cx).text(cx);
17259
17260        let rename = self.semantics_provider.as_ref()?.perform_rename(
17261            &buffer,
17262            start,
17263            new_name.clone(),
17264            cx,
17265        )?;
17266
17267        Some(cx.spawn_in(window, async move |editor, cx| {
17268            let project_transaction = rename.await?;
17269            Self::open_project_transaction(
17270                &editor,
17271                workspace,
17272                project_transaction,
17273                format!("Rename: {}{}", old_name, new_name),
17274                cx,
17275            )
17276            .await?;
17277
17278            editor.update(cx, |editor, cx| {
17279                editor.refresh_document_highlights(cx);
17280            })?;
17281            Ok(())
17282        }))
17283    }
17284
17285    fn take_rename(
17286        &mut self,
17287        moving_cursor: bool,
17288        window: &mut Window,
17289        cx: &mut Context<Self>,
17290    ) -> Option<RenameState> {
17291        let rename = self.pending_rename.take()?;
17292        if rename.editor.focus_handle(cx).is_focused(window) {
17293            window.focus(&self.focus_handle);
17294        }
17295
17296        self.remove_blocks(
17297            [rename.block_id].into_iter().collect(),
17298            Some(Autoscroll::fit()),
17299            cx,
17300        );
17301        self.clear_highlights::<Rename>(cx);
17302        self.show_local_selections = true;
17303
17304        if moving_cursor {
17305            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17306                editor
17307                    .selections
17308                    .newest::<usize>(&editor.display_snapshot(cx))
17309                    .head()
17310            });
17311
17312            // Update the selection to match the position of the selection inside
17313            // the rename editor.
17314            let snapshot = self.buffer.read(cx).read(cx);
17315            let rename_range = rename.range.to_offset(&snapshot);
17316            let cursor_in_editor = snapshot
17317                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17318                .min(rename_range.end);
17319            drop(snapshot);
17320
17321            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17322                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17323            });
17324        } else {
17325            self.refresh_document_highlights(cx);
17326        }
17327
17328        Some(rename)
17329    }
17330
17331    pub fn pending_rename(&self) -> Option<&RenameState> {
17332        self.pending_rename.as_ref()
17333    }
17334
17335    fn format(
17336        &mut self,
17337        _: &Format,
17338        window: &mut Window,
17339        cx: &mut Context<Self>,
17340    ) -> Option<Task<Result<()>>> {
17341        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17342
17343        let project = match &self.project {
17344            Some(project) => project.clone(),
17345            None => return None,
17346        };
17347
17348        Some(self.perform_format(
17349            project,
17350            FormatTrigger::Manual,
17351            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17352            window,
17353            cx,
17354        ))
17355    }
17356
17357    fn format_selections(
17358        &mut self,
17359        _: &FormatSelections,
17360        window: &mut Window,
17361        cx: &mut Context<Self>,
17362    ) -> Option<Task<Result<()>>> {
17363        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17364
17365        let project = match &self.project {
17366            Some(project) => project.clone(),
17367            None => return None,
17368        };
17369
17370        let ranges = self
17371            .selections
17372            .all_adjusted(&self.display_snapshot(cx))
17373            .into_iter()
17374            .map(|selection| selection.range())
17375            .collect_vec();
17376
17377        Some(self.perform_format(
17378            project,
17379            FormatTrigger::Manual,
17380            FormatTarget::Ranges(ranges),
17381            window,
17382            cx,
17383        ))
17384    }
17385
17386    fn perform_format(
17387        &mut self,
17388        project: Entity<Project>,
17389        trigger: FormatTrigger,
17390        target: FormatTarget,
17391        window: &mut Window,
17392        cx: &mut Context<Self>,
17393    ) -> Task<Result<()>> {
17394        let buffer = self.buffer.clone();
17395        let (buffers, target) = match target {
17396            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17397            FormatTarget::Ranges(selection_ranges) => {
17398                let multi_buffer = buffer.read(cx);
17399                let snapshot = multi_buffer.read(cx);
17400                let mut buffers = HashSet::default();
17401                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17402                    BTreeMap::new();
17403                for selection_range in selection_ranges {
17404                    for (buffer, buffer_range, _) in
17405                        snapshot.range_to_buffer_ranges(selection_range)
17406                    {
17407                        let buffer_id = buffer.remote_id();
17408                        let start = buffer.anchor_before(buffer_range.start);
17409                        let end = buffer.anchor_after(buffer_range.end);
17410                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17411                        buffer_id_to_ranges
17412                            .entry(buffer_id)
17413                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17414                            .or_insert_with(|| vec![start..end]);
17415                    }
17416                }
17417                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17418            }
17419        };
17420
17421        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17422        let selections_prev = transaction_id_prev
17423            .and_then(|transaction_id_prev| {
17424                // default to selections as they were after the last edit, if we have them,
17425                // instead of how they are now.
17426                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17427                // will take you back to where you made the last edit, instead of staying where you scrolled
17428                self.selection_history
17429                    .transaction(transaction_id_prev)
17430                    .map(|t| t.0.clone())
17431            })
17432            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17433
17434        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17435        let format = project.update(cx, |project, cx| {
17436            project.format(buffers, target, true, trigger, cx)
17437        });
17438
17439        cx.spawn_in(window, async move |editor, cx| {
17440            let transaction = futures::select_biased! {
17441                transaction = format.log_err().fuse() => transaction,
17442                () = timeout => {
17443                    log::warn!("timed out waiting for formatting");
17444                    None
17445                }
17446            };
17447
17448            buffer
17449                .update(cx, |buffer, cx| {
17450                    if let Some(transaction) = transaction
17451                        && !buffer.is_singleton()
17452                    {
17453                        buffer.push_transaction(&transaction.0, cx);
17454                    }
17455                    cx.notify();
17456                })
17457                .ok();
17458
17459            if let Some(transaction_id_now) =
17460                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17461            {
17462                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17463                if has_new_transaction {
17464                    _ = editor.update(cx, |editor, _| {
17465                        editor
17466                            .selection_history
17467                            .insert_transaction(transaction_id_now, selections_prev);
17468                    });
17469                }
17470            }
17471
17472            Ok(())
17473        })
17474    }
17475
17476    fn organize_imports(
17477        &mut self,
17478        _: &OrganizeImports,
17479        window: &mut Window,
17480        cx: &mut Context<Self>,
17481    ) -> Option<Task<Result<()>>> {
17482        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17483        let project = match &self.project {
17484            Some(project) => project.clone(),
17485            None => return None,
17486        };
17487        Some(self.perform_code_action_kind(
17488            project,
17489            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17490            window,
17491            cx,
17492        ))
17493    }
17494
17495    fn perform_code_action_kind(
17496        &mut self,
17497        project: Entity<Project>,
17498        kind: CodeActionKind,
17499        window: &mut Window,
17500        cx: &mut Context<Self>,
17501    ) -> Task<Result<()>> {
17502        let buffer = self.buffer.clone();
17503        let buffers = buffer.read(cx).all_buffers();
17504        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17505        let apply_action = project.update(cx, |project, cx| {
17506            project.apply_code_action_kind(buffers, kind, true, cx)
17507        });
17508        cx.spawn_in(window, async move |_, cx| {
17509            let transaction = futures::select_biased! {
17510                () = timeout => {
17511                    log::warn!("timed out waiting for executing code action");
17512                    None
17513                }
17514                transaction = apply_action.log_err().fuse() => transaction,
17515            };
17516            buffer
17517                .update(cx, |buffer, cx| {
17518                    // check if we need this
17519                    if let Some(transaction) = transaction
17520                        && !buffer.is_singleton()
17521                    {
17522                        buffer.push_transaction(&transaction.0, cx);
17523                    }
17524                    cx.notify();
17525                })
17526                .ok();
17527            Ok(())
17528        })
17529    }
17530
17531    pub fn restart_language_server(
17532        &mut self,
17533        _: &RestartLanguageServer,
17534        _: &mut Window,
17535        cx: &mut Context<Self>,
17536    ) {
17537        if let Some(project) = self.project.clone() {
17538            self.buffer.update(cx, |multi_buffer, cx| {
17539                project.update(cx, |project, cx| {
17540                    project.restart_language_servers_for_buffers(
17541                        multi_buffer.all_buffers().into_iter().collect(),
17542                        HashSet::default(),
17543                        cx,
17544                    );
17545                });
17546            })
17547        }
17548    }
17549
17550    pub fn stop_language_server(
17551        &mut self,
17552        _: &StopLanguageServer,
17553        _: &mut Window,
17554        cx: &mut Context<Self>,
17555    ) {
17556        if let Some(project) = self.project.clone() {
17557            self.buffer.update(cx, |multi_buffer, cx| {
17558                project.update(cx, |project, cx| {
17559                    project.stop_language_servers_for_buffers(
17560                        multi_buffer.all_buffers().into_iter().collect(),
17561                        HashSet::default(),
17562                        cx,
17563                    );
17564                });
17565            });
17566            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17567        }
17568    }
17569
17570    fn cancel_language_server_work(
17571        workspace: &mut Workspace,
17572        _: &actions::CancelLanguageServerWork,
17573        _: &mut Window,
17574        cx: &mut Context<Workspace>,
17575    ) {
17576        let project = workspace.project();
17577        let buffers = workspace
17578            .active_item(cx)
17579            .and_then(|item| item.act_as::<Editor>(cx))
17580            .map_or(HashSet::default(), |editor| {
17581                editor.read(cx).buffer.read(cx).all_buffers()
17582            });
17583        project.update(cx, |project, cx| {
17584            project.cancel_language_server_work_for_buffers(buffers, cx);
17585        });
17586    }
17587
17588    fn show_character_palette(
17589        &mut self,
17590        _: &ShowCharacterPalette,
17591        window: &mut Window,
17592        _: &mut Context<Self>,
17593    ) {
17594        window.show_character_palette();
17595    }
17596
17597    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17598        if !self.diagnostics_enabled() {
17599            return;
17600        }
17601
17602        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17603            let buffer = self.buffer.read(cx).snapshot(cx);
17604            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17605            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17606            let is_valid = buffer
17607                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17608                .any(|entry| {
17609                    entry.diagnostic.is_primary
17610                        && !entry.range.is_empty()
17611                        && entry.range.start == primary_range_start
17612                        && entry.diagnostic.message == active_diagnostics.active_message
17613                });
17614
17615            if !is_valid {
17616                self.dismiss_diagnostics(cx);
17617            }
17618        }
17619    }
17620
17621    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17622        match &self.active_diagnostics {
17623            ActiveDiagnostic::Group(group) => Some(group),
17624            _ => None,
17625        }
17626    }
17627
17628    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17629        if !self.diagnostics_enabled() {
17630            return;
17631        }
17632        self.dismiss_diagnostics(cx);
17633        self.active_diagnostics = ActiveDiagnostic::All;
17634    }
17635
17636    fn activate_diagnostics(
17637        &mut self,
17638        buffer_id: BufferId,
17639        diagnostic: DiagnosticEntryRef<'_, usize>,
17640        window: &mut Window,
17641        cx: &mut Context<Self>,
17642    ) {
17643        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17644            return;
17645        }
17646        self.dismiss_diagnostics(cx);
17647        let snapshot = self.snapshot(window, cx);
17648        let buffer = self.buffer.read(cx).snapshot(cx);
17649        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17650            return;
17651        };
17652
17653        let diagnostic_group = buffer
17654            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17655            .collect::<Vec<_>>();
17656
17657        let blocks =
17658            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17659
17660        let blocks = self.display_map.update(cx, |display_map, cx| {
17661            display_map.insert_blocks(blocks, cx).into_iter().collect()
17662        });
17663        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17664            active_range: buffer.anchor_before(diagnostic.range.start)
17665                ..buffer.anchor_after(diagnostic.range.end),
17666            active_message: diagnostic.diagnostic.message.clone(),
17667            group_id: diagnostic.diagnostic.group_id,
17668            blocks,
17669        });
17670        cx.notify();
17671    }
17672
17673    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17674        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17675            return;
17676        };
17677
17678        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17679        if let ActiveDiagnostic::Group(group) = prev {
17680            self.display_map.update(cx, |display_map, cx| {
17681                display_map.remove_blocks(group.blocks, cx);
17682            });
17683            cx.notify();
17684        }
17685    }
17686
17687    /// Disable inline diagnostics rendering for this editor.
17688    pub fn disable_inline_diagnostics(&mut self) {
17689        self.inline_diagnostics_enabled = false;
17690        self.inline_diagnostics_update = Task::ready(());
17691        self.inline_diagnostics.clear();
17692    }
17693
17694    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17695        self.diagnostics_enabled = false;
17696        self.dismiss_diagnostics(cx);
17697        self.inline_diagnostics_update = Task::ready(());
17698        self.inline_diagnostics.clear();
17699    }
17700
17701    pub fn disable_word_completions(&mut self) {
17702        self.word_completions_enabled = false;
17703    }
17704
17705    pub fn diagnostics_enabled(&self) -> bool {
17706        self.diagnostics_enabled && self.mode.is_full()
17707    }
17708
17709    pub fn inline_diagnostics_enabled(&self) -> bool {
17710        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17711    }
17712
17713    pub fn show_inline_diagnostics(&self) -> bool {
17714        self.show_inline_diagnostics
17715    }
17716
17717    pub fn toggle_inline_diagnostics(
17718        &mut self,
17719        _: &ToggleInlineDiagnostics,
17720        window: &mut Window,
17721        cx: &mut Context<Editor>,
17722    ) {
17723        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17724        self.refresh_inline_diagnostics(false, window, cx);
17725    }
17726
17727    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17728        self.diagnostics_max_severity = severity;
17729        self.display_map.update(cx, |display_map, _| {
17730            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17731        });
17732    }
17733
17734    pub fn toggle_diagnostics(
17735        &mut self,
17736        _: &ToggleDiagnostics,
17737        window: &mut Window,
17738        cx: &mut Context<Editor>,
17739    ) {
17740        if !self.diagnostics_enabled() {
17741            return;
17742        }
17743
17744        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17745            EditorSettings::get_global(cx)
17746                .diagnostics_max_severity
17747                .filter(|severity| severity != &DiagnosticSeverity::Off)
17748                .unwrap_or(DiagnosticSeverity::Hint)
17749        } else {
17750            DiagnosticSeverity::Off
17751        };
17752        self.set_max_diagnostics_severity(new_severity, cx);
17753        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17754            self.active_diagnostics = ActiveDiagnostic::None;
17755            self.inline_diagnostics_update = Task::ready(());
17756            self.inline_diagnostics.clear();
17757        } else {
17758            self.refresh_inline_diagnostics(false, window, cx);
17759        }
17760
17761        cx.notify();
17762    }
17763
17764    pub fn toggle_minimap(
17765        &mut self,
17766        _: &ToggleMinimap,
17767        window: &mut Window,
17768        cx: &mut Context<Editor>,
17769    ) {
17770        if self.supports_minimap(cx) {
17771            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17772        }
17773    }
17774
17775    fn refresh_inline_diagnostics(
17776        &mut self,
17777        debounce: bool,
17778        window: &mut Window,
17779        cx: &mut Context<Self>,
17780    ) {
17781        let max_severity = ProjectSettings::get_global(cx)
17782            .diagnostics
17783            .inline
17784            .max_severity
17785            .unwrap_or(self.diagnostics_max_severity);
17786
17787        if !self.inline_diagnostics_enabled()
17788            || !self.diagnostics_enabled()
17789            || !self.show_inline_diagnostics
17790            || max_severity == DiagnosticSeverity::Off
17791        {
17792            self.inline_diagnostics_update = Task::ready(());
17793            self.inline_diagnostics.clear();
17794            return;
17795        }
17796
17797        let debounce_ms = ProjectSettings::get_global(cx)
17798            .diagnostics
17799            .inline
17800            .update_debounce_ms;
17801        let debounce = if debounce && debounce_ms > 0 {
17802            Some(Duration::from_millis(debounce_ms))
17803        } else {
17804            None
17805        };
17806        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17807            if let Some(debounce) = debounce {
17808                cx.background_executor().timer(debounce).await;
17809            }
17810            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17811                editor
17812                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17813                    .ok()
17814            }) else {
17815                return;
17816            };
17817
17818            let new_inline_diagnostics = cx
17819                .background_spawn(async move {
17820                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17821                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17822                        let message = diagnostic_entry
17823                            .diagnostic
17824                            .message
17825                            .split_once('\n')
17826                            .map(|(line, _)| line)
17827                            .map(SharedString::new)
17828                            .unwrap_or_else(|| {
17829                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17830                            });
17831                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17832                        let (Ok(i) | Err(i)) = inline_diagnostics
17833                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17834                        inline_diagnostics.insert(
17835                            i,
17836                            (
17837                                start_anchor,
17838                                InlineDiagnostic {
17839                                    message,
17840                                    group_id: diagnostic_entry.diagnostic.group_id,
17841                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17842                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17843                                    severity: diagnostic_entry.diagnostic.severity,
17844                                },
17845                            ),
17846                        );
17847                    }
17848                    inline_diagnostics
17849                })
17850                .await;
17851
17852            editor
17853                .update(cx, |editor, cx| {
17854                    editor.inline_diagnostics = new_inline_diagnostics;
17855                    cx.notify();
17856                })
17857                .ok();
17858        });
17859    }
17860
17861    fn pull_diagnostics(
17862        &mut self,
17863        buffer_id: Option<BufferId>,
17864        window: &Window,
17865        cx: &mut Context<Self>,
17866    ) -> Option<()> {
17867        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
17868            return None;
17869        }
17870        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17871            .diagnostics
17872            .lsp_pull_diagnostics;
17873        if !pull_diagnostics_settings.enabled {
17874            return None;
17875        }
17876        let project = self.project()?.downgrade();
17877        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17878        let mut buffers = self.buffer.read(cx).all_buffers();
17879        buffers.retain(|buffer| {
17880            let buffer_id_to_retain = buffer.read(cx).remote_id();
17881            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17882                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17883        });
17884        if buffers.is_empty() {
17885            self.pull_diagnostics_task = Task::ready(());
17886            return None;
17887        }
17888
17889        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17890            cx.background_executor().timer(debounce).await;
17891
17892            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17893                buffers
17894                    .into_iter()
17895                    .filter_map(|buffer| {
17896                        project
17897                            .update(cx, |project, cx| {
17898                                project.lsp_store().update(cx, |lsp_store, cx| {
17899                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17900                                })
17901                            })
17902                            .ok()
17903                    })
17904                    .collect::<FuturesUnordered<_>>()
17905            }) else {
17906                return;
17907            };
17908
17909            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17910                match pull_task {
17911                    Ok(()) => {
17912                        if editor
17913                            .update_in(cx, |editor, window, cx| {
17914                                editor.update_diagnostics_state(window, cx);
17915                            })
17916                            .is_err()
17917                        {
17918                            return;
17919                        }
17920                    }
17921                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17922                }
17923            }
17924        });
17925
17926        Some(())
17927    }
17928
17929    pub fn set_selections_from_remote(
17930        &mut self,
17931        selections: Vec<Selection<Anchor>>,
17932        pending_selection: Option<Selection<Anchor>>,
17933        window: &mut Window,
17934        cx: &mut Context<Self>,
17935    ) {
17936        let old_cursor_position = self.selections.newest_anchor().head();
17937        self.selections.change_with(cx, |s| {
17938            s.select_anchors(selections);
17939            if let Some(pending_selection) = pending_selection {
17940                s.set_pending(pending_selection, SelectMode::Character);
17941            } else {
17942                s.clear_pending();
17943            }
17944        });
17945        self.selections_did_change(
17946            false,
17947            &old_cursor_position,
17948            SelectionEffects::default(),
17949            window,
17950            cx,
17951        );
17952    }
17953
17954    pub fn transact(
17955        &mut self,
17956        window: &mut Window,
17957        cx: &mut Context<Self>,
17958        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17959    ) -> Option<TransactionId> {
17960        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17961            this.start_transaction_at(Instant::now(), window, cx);
17962            update(this, window, cx);
17963            this.end_transaction_at(Instant::now(), cx)
17964        })
17965    }
17966
17967    pub fn start_transaction_at(
17968        &mut self,
17969        now: Instant,
17970        window: &mut Window,
17971        cx: &mut Context<Self>,
17972    ) -> Option<TransactionId> {
17973        self.end_selection(window, cx);
17974        if let Some(tx_id) = self
17975            .buffer
17976            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17977        {
17978            self.selection_history
17979                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17980            cx.emit(EditorEvent::TransactionBegun {
17981                transaction_id: tx_id,
17982            });
17983            Some(tx_id)
17984        } else {
17985            None
17986        }
17987    }
17988
17989    pub fn end_transaction_at(
17990        &mut self,
17991        now: Instant,
17992        cx: &mut Context<Self>,
17993    ) -> Option<TransactionId> {
17994        if let Some(transaction_id) = self
17995            .buffer
17996            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17997        {
17998            if let Some((_, end_selections)) =
17999                self.selection_history.transaction_mut(transaction_id)
18000            {
18001                *end_selections = Some(self.selections.disjoint_anchors_arc());
18002            } else {
18003                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18004            }
18005
18006            cx.emit(EditorEvent::Edited { transaction_id });
18007            Some(transaction_id)
18008        } else {
18009            None
18010        }
18011    }
18012
18013    pub fn modify_transaction_selection_history(
18014        &mut self,
18015        transaction_id: TransactionId,
18016        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18017    ) -> bool {
18018        self.selection_history
18019            .transaction_mut(transaction_id)
18020            .map(modify)
18021            .is_some()
18022    }
18023
18024    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18025        if self.selection_mark_mode {
18026            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18027                s.move_with(|_, sel| {
18028                    sel.collapse_to(sel.head(), SelectionGoal::None);
18029                });
18030            })
18031        }
18032        self.selection_mark_mode = true;
18033        cx.notify();
18034    }
18035
18036    pub fn swap_selection_ends(
18037        &mut self,
18038        _: &actions::SwapSelectionEnds,
18039        window: &mut Window,
18040        cx: &mut Context<Self>,
18041    ) {
18042        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18043            s.move_with(|_, sel| {
18044                if sel.start != sel.end {
18045                    sel.reversed = !sel.reversed
18046                }
18047            });
18048        });
18049        self.request_autoscroll(Autoscroll::newest(), cx);
18050        cx.notify();
18051    }
18052
18053    pub fn toggle_focus(
18054        workspace: &mut Workspace,
18055        _: &actions::ToggleFocus,
18056        window: &mut Window,
18057        cx: &mut Context<Workspace>,
18058    ) {
18059        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18060            return;
18061        };
18062        workspace.activate_item(&item, true, true, window, cx);
18063    }
18064
18065    pub fn toggle_fold(
18066        &mut self,
18067        _: &actions::ToggleFold,
18068        window: &mut Window,
18069        cx: &mut Context<Self>,
18070    ) {
18071        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18072            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18073            let selection = self.selections.newest::<Point>(&display_map);
18074
18075            let range = if selection.is_empty() {
18076                let point = selection.head().to_display_point(&display_map);
18077                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18078                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18079                    .to_point(&display_map);
18080                start..end
18081            } else {
18082                selection.range()
18083            };
18084            if display_map.folds_in_range(range).next().is_some() {
18085                self.unfold_lines(&Default::default(), window, cx)
18086            } else {
18087                self.fold(&Default::default(), window, cx)
18088            }
18089        } else {
18090            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18091            let buffer_ids: HashSet<_> = self
18092                .selections
18093                .disjoint_anchor_ranges()
18094                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18095                .collect();
18096
18097            let should_unfold = buffer_ids
18098                .iter()
18099                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18100
18101            for buffer_id in buffer_ids {
18102                if should_unfold {
18103                    self.unfold_buffer(buffer_id, cx);
18104                } else {
18105                    self.fold_buffer(buffer_id, cx);
18106                }
18107            }
18108        }
18109    }
18110
18111    pub fn toggle_fold_recursive(
18112        &mut self,
18113        _: &actions::ToggleFoldRecursive,
18114        window: &mut Window,
18115        cx: &mut Context<Self>,
18116    ) {
18117        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18118
18119        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18120        let range = if selection.is_empty() {
18121            let point = selection.head().to_display_point(&display_map);
18122            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18123            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18124                .to_point(&display_map);
18125            start..end
18126        } else {
18127            selection.range()
18128        };
18129        if display_map.folds_in_range(range).next().is_some() {
18130            self.unfold_recursive(&Default::default(), window, cx)
18131        } else {
18132            self.fold_recursive(&Default::default(), window, cx)
18133        }
18134    }
18135
18136    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18137        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18138            let mut to_fold = Vec::new();
18139            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18140            let selections = self.selections.all_adjusted(&display_map);
18141
18142            for selection in selections {
18143                let range = selection.range().sorted();
18144                let buffer_start_row = range.start.row;
18145
18146                if range.start.row != range.end.row {
18147                    let mut found = false;
18148                    let mut row = range.start.row;
18149                    while row <= range.end.row {
18150                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18151                        {
18152                            found = true;
18153                            row = crease.range().end.row + 1;
18154                            to_fold.push(crease);
18155                        } else {
18156                            row += 1
18157                        }
18158                    }
18159                    if found {
18160                        continue;
18161                    }
18162                }
18163
18164                for row in (0..=range.start.row).rev() {
18165                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18166                        && crease.range().end.row >= buffer_start_row
18167                    {
18168                        to_fold.push(crease);
18169                        if row <= range.start.row {
18170                            break;
18171                        }
18172                    }
18173                }
18174            }
18175
18176            self.fold_creases(to_fold, true, window, cx);
18177        } else {
18178            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18179            let buffer_ids = self
18180                .selections
18181                .disjoint_anchor_ranges()
18182                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18183                .collect::<HashSet<_>>();
18184            for buffer_id in buffer_ids {
18185                self.fold_buffer(buffer_id, cx);
18186            }
18187        }
18188    }
18189
18190    pub fn toggle_fold_all(
18191        &mut self,
18192        _: &actions::ToggleFoldAll,
18193        window: &mut Window,
18194        cx: &mut Context<Self>,
18195    ) {
18196        if self.buffer.read(cx).is_singleton() {
18197            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18198            let has_folds = display_map
18199                .folds_in_range(0..display_map.buffer_snapshot().len())
18200                .next()
18201                .is_some();
18202
18203            if has_folds {
18204                self.unfold_all(&actions::UnfoldAll, window, cx);
18205            } else {
18206                self.fold_all(&actions::FoldAll, window, cx);
18207            }
18208        } else {
18209            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18210            let should_unfold = buffer_ids
18211                .iter()
18212                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18213
18214            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18215                editor
18216                    .update_in(cx, |editor, _, cx| {
18217                        for buffer_id in buffer_ids {
18218                            if should_unfold {
18219                                editor.unfold_buffer(buffer_id, cx);
18220                            } else {
18221                                editor.fold_buffer(buffer_id, cx);
18222                            }
18223                        }
18224                    })
18225                    .ok();
18226            });
18227        }
18228    }
18229
18230    fn fold_at_level(
18231        &mut self,
18232        fold_at: &FoldAtLevel,
18233        window: &mut Window,
18234        cx: &mut Context<Self>,
18235    ) {
18236        if !self.buffer.read(cx).is_singleton() {
18237            return;
18238        }
18239
18240        let fold_at_level = fold_at.0;
18241        let snapshot = self.buffer.read(cx).snapshot(cx);
18242        let mut to_fold = Vec::new();
18243        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18244
18245        let row_ranges_to_keep: Vec<Range<u32>> = self
18246            .selections
18247            .all::<Point>(&self.display_snapshot(cx))
18248            .into_iter()
18249            .map(|sel| sel.start.row..sel.end.row)
18250            .collect();
18251
18252        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18253            while start_row < end_row {
18254                match self
18255                    .snapshot(window, cx)
18256                    .crease_for_buffer_row(MultiBufferRow(start_row))
18257                {
18258                    Some(crease) => {
18259                        let nested_start_row = crease.range().start.row + 1;
18260                        let nested_end_row = crease.range().end.row;
18261
18262                        if current_level < fold_at_level {
18263                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18264                        } else if current_level == fold_at_level {
18265                            // Fold iff there is no selection completely contained within the fold region
18266                            if !row_ranges_to_keep.iter().any(|selection| {
18267                                selection.end >= nested_start_row
18268                                    && selection.start <= nested_end_row
18269                            }) {
18270                                to_fold.push(crease);
18271                            }
18272                        }
18273
18274                        start_row = nested_end_row + 1;
18275                    }
18276                    None => start_row += 1,
18277                }
18278            }
18279        }
18280
18281        self.fold_creases(to_fold, true, window, cx);
18282    }
18283
18284    pub fn fold_at_level_1(
18285        &mut self,
18286        _: &actions::FoldAtLevel1,
18287        window: &mut Window,
18288        cx: &mut Context<Self>,
18289    ) {
18290        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18291    }
18292
18293    pub fn fold_at_level_2(
18294        &mut self,
18295        _: &actions::FoldAtLevel2,
18296        window: &mut Window,
18297        cx: &mut Context<Self>,
18298    ) {
18299        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18300    }
18301
18302    pub fn fold_at_level_3(
18303        &mut self,
18304        _: &actions::FoldAtLevel3,
18305        window: &mut Window,
18306        cx: &mut Context<Self>,
18307    ) {
18308        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18309    }
18310
18311    pub fn fold_at_level_4(
18312        &mut self,
18313        _: &actions::FoldAtLevel4,
18314        window: &mut Window,
18315        cx: &mut Context<Self>,
18316    ) {
18317        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18318    }
18319
18320    pub fn fold_at_level_5(
18321        &mut self,
18322        _: &actions::FoldAtLevel5,
18323        window: &mut Window,
18324        cx: &mut Context<Self>,
18325    ) {
18326        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18327    }
18328
18329    pub fn fold_at_level_6(
18330        &mut self,
18331        _: &actions::FoldAtLevel6,
18332        window: &mut Window,
18333        cx: &mut Context<Self>,
18334    ) {
18335        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18336    }
18337
18338    pub fn fold_at_level_7(
18339        &mut self,
18340        _: &actions::FoldAtLevel7,
18341        window: &mut Window,
18342        cx: &mut Context<Self>,
18343    ) {
18344        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18345    }
18346
18347    pub fn fold_at_level_8(
18348        &mut self,
18349        _: &actions::FoldAtLevel8,
18350        window: &mut Window,
18351        cx: &mut Context<Self>,
18352    ) {
18353        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18354    }
18355
18356    pub fn fold_at_level_9(
18357        &mut self,
18358        _: &actions::FoldAtLevel9,
18359        window: &mut Window,
18360        cx: &mut Context<Self>,
18361    ) {
18362        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18363    }
18364
18365    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18366        if self.buffer.read(cx).is_singleton() {
18367            let mut fold_ranges = Vec::new();
18368            let snapshot = self.buffer.read(cx).snapshot(cx);
18369
18370            for row in 0..snapshot.max_row().0 {
18371                if let Some(foldable_range) = self
18372                    .snapshot(window, cx)
18373                    .crease_for_buffer_row(MultiBufferRow(row))
18374                {
18375                    fold_ranges.push(foldable_range);
18376                }
18377            }
18378
18379            self.fold_creases(fold_ranges, true, window, cx);
18380        } else {
18381            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18382                editor
18383                    .update_in(cx, |editor, _, cx| {
18384                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18385                            editor.fold_buffer(buffer_id, cx);
18386                        }
18387                    })
18388                    .ok();
18389            });
18390        }
18391    }
18392
18393    pub fn fold_function_bodies(
18394        &mut self,
18395        _: &actions::FoldFunctionBodies,
18396        window: &mut Window,
18397        cx: &mut Context<Self>,
18398    ) {
18399        let snapshot = self.buffer.read(cx).snapshot(cx);
18400
18401        let ranges = snapshot
18402            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18403            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18404            .collect::<Vec<_>>();
18405
18406        let creases = ranges
18407            .into_iter()
18408            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18409            .collect();
18410
18411        self.fold_creases(creases, true, window, cx);
18412    }
18413
18414    pub fn fold_recursive(
18415        &mut self,
18416        _: &actions::FoldRecursive,
18417        window: &mut Window,
18418        cx: &mut Context<Self>,
18419    ) {
18420        let mut to_fold = Vec::new();
18421        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18422        let selections = self.selections.all_adjusted(&display_map);
18423
18424        for selection in selections {
18425            let range = selection.range().sorted();
18426            let buffer_start_row = range.start.row;
18427
18428            if range.start.row != range.end.row {
18429                let mut found = false;
18430                for row in range.start.row..=range.end.row {
18431                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18432                        found = true;
18433                        to_fold.push(crease);
18434                    }
18435                }
18436                if found {
18437                    continue;
18438                }
18439            }
18440
18441            for row in (0..=range.start.row).rev() {
18442                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18443                    if crease.range().end.row >= buffer_start_row {
18444                        to_fold.push(crease);
18445                    } else {
18446                        break;
18447                    }
18448                }
18449            }
18450        }
18451
18452        self.fold_creases(to_fold, true, window, cx);
18453    }
18454
18455    pub fn fold_at(
18456        &mut self,
18457        buffer_row: MultiBufferRow,
18458        window: &mut Window,
18459        cx: &mut Context<Self>,
18460    ) {
18461        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18462
18463        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18464            let autoscroll = self
18465                .selections
18466                .all::<Point>(&display_map)
18467                .iter()
18468                .any(|selection| crease.range().overlaps(&selection.range()));
18469
18470            self.fold_creases(vec![crease], autoscroll, window, cx);
18471        }
18472    }
18473
18474    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18475        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18476            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18477            let buffer = display_map.buffer_snapshot();
18478            let selections = self.selections.all::<Point>(&display_map);
18479            let ranges = selections
18480                .iter()
18481                .map(|s| {
18482                    let range = s.display_range(&display_map).sorted();
18483                    let mut start = range.start.to_point(&display_map);
18484                    let mut end = range.end.to_point(&display_map);
18485                    start.column = 0;
18486                    end.column = buffer.line_len(MultiBufferRow(end.row));
18487                    start..end
18488                })
18489                .collect::<Vec<_>>();
18490
18491            self.unfold_ranges(&ranges, true, true, cx);
18492        } else {
18493            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18494            let buffer_ids = self
18495                .selections
18496                .disjoint_anchor_ranges()
18497                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18498                .collect::<HashSet<_>>();
18499            for buffer_id in buffer_ids {
18500                self.unfold_buffer(buffer_id, cx);
18501            }
18502        }
18503    }
18504
18505    pub fn unfold_recursive(
18506        &mut self,
18507        _: &UnfoldRecursive,
18508        _window: &mut Window,
18509        cx: &mut Context<Self>,
18510    ) {
18511        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18512        let selections = self.selections.all::<Point>(&display_map);
18513        let ranges = selections
18514            .iter()
18515            .map(|s| {
18516                let mut range = s.display_range(&display_map).sorted();
18517                *range.start.column_mut() = 0;
18518                *range.end.column_mut() = display_map.line_len(range.end.row());
18519                let start = range.start.to_point(&display_map);
18520                let end = range.end.to_point(&display_map);
18521                start..end
18522            })
18523            .collect::<Vec<_>>();
18524
18525        self.unfold_ranges(&ranges, true, true, cx);
18526    }
18527
18528    pub fn unfold_at(
18529        &mut self,
18530        buffer_row: MultiBufferRow,
18531        _window: &mut Window,
18532        cx: &mut Context<Self>,
18533    ) {
18534        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18535
18536        let intersection_range = Point::new(buffer_row.0, 0)
18537            ..Point::new(
18538                buffer_row.0,
18539                display_map.buffer_snapshot().line_len(buffer_row),
18540            );
18541
18542        let autoscroll = self
18543            .selections
18544            .all::<Point>(&display_map)
18545            .iter()
18546            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18547
18548        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18549    }
18550
18551    pub fn unfold_all(
18552        &mut self,
18553        _: &actions::UnfoldAll,
18554        _window: &mut Window,
18555        cx: &mut Context<Self>,
18556    ) {
18557        if self.buffer.read(cx).is_singleton() {
18558            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18559            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18560        } else {
18561            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18562                editor
18563                    .update(cx, |editor, cx| {
18564                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18565                            editor.unfold_buffer(buffer_id, cx);
18566                        }
18567                    })
18568                    .ok();
18569            });
18570        }
18571    }
18572
18573    pub fn fold_selected_ranges(
18574        &mut self,
18575        _: &FoldSelectedRanges,
18576        window: &mut Window,
18577        cx: &mut Context<Self>,
18578    ) {
18579        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18580        let selections = self.selections.all_adjusted(&display_map);
18581        let ranges = selections
18582            .into_iter()
18583            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18584            .collect::<Vec<_>>();
18585        self.fold_creases(ranges, true, window, cx);
18586    }
18587
18588    pub fn fold_ranges<T: ToOffset + Clone>(
18589        &mut self,
18590        ranges: Vec<Range<T>>,
18591        auto_scroll: bool,
18592        window: &mut Window,
18593        cx: &mut Context<Self>,
18594    ) {
18595        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18596        let ranges = ranges
18597            .into_iter()
18598            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18599            .collect::<Vec<_>>();
18600        self.fold_creases(ranges, auto_scroll, window, cx);
18601    }
18602
18603    pub fn fold_creases<T: ToOffset + Clone>(
18604        &mut self,
18605        creases: Vec<Crease<T>>,
18606        auto_scroll: bool,
18607        _window: &mut Window,
18608        cx: &mut Context<Self>,
18609    ) {
18610        if creases.is_empty() {
18611            return;
18612        }
18613
18614        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18615
18616        if auto_scroll {
18617            self.request_autoscroll(Autoscroll::fit(), cx);
18618        }
18619
18620        cx.notify();
18621
18622        self.scrollbar_marker_state.dirty = true;
18623        self.folds_did_change(cx);
18624    }
18625
18626    /// Removes any folds whose ranges intersect any of the given ranges.
18627    pub fn unfold_ranges<T: ToOffset + Clone>(
18628        &mut self,
18629        ranges: &[Range<T>],
18630        inclusive: bool,
18631        auto_scroll: bool,
18632        cx: &mut Context<Self>,
18633    ) {
18634        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18635            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18636        });
18637        self.folds_did_change(cx);
18638    }
18639
18640    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18641        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18642            return;
18643        }
18644        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18645        self.display_map.update(cx, |display_map, cx| {
18646            display_map.fold_buffers([buffer_id], cx)
18647        });
18648        cx.emit(EditorEvent::BufferFoldToggled {
18649            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18650            folded: true,
18651        });
18652        cx.notify();
18653    }
18654
18655    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18656        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18657            return;
18658        }
18659        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18660        self.display_map.update(cx, |display_map, cx| {
18661            display_map.unfold_buffers([buffer_id], cx);
18662        });
18663        cx.emit(EditorEvent::BufferFoldToggled {
18664            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18665            folded: false,
18666        });
18667        cx.notify();
18668    }
18669
18670    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18671        self.display_map.read(cx).is_buffer_folded(buffer)
18672    }
18673
18674    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18675        self.display_map.read(cx).folded_buffers()
18676    }
18677
18678    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18679        self.display_map.update(cx, |display_map, cx| {
18680            display_map.disable_header_for_buffer(buffer_id, cx);
18681        });
18682        cx.notify();
18683    }
18684
18685    /// Removes any folds with the given ranges.
18686    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18687        &mut self,
18688        ranges: &[Range<T>],
18689        type_id: TypeId,
18690        auto_scroll: bool,
18691        cx: &mut Context<Self>,
18692    ) {
18693        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18694            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18695        });
18696        self.folds_did_change(cx);
18697    }
18698
18699    fn remove_folds_with<T: ToOffset + Clone>(
18700        &mut self,
18701        ranges: &[Range<T>],
18702        auto_scroll: bool,
18703        cx: &mut Context<Self>,
18704        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18705    ) {
18706        if ranges.is_empty() {
18707            return;
18708        }
18709
18710        let mut buffers_affected = HashSet::default();
18711        let multi_buffer = self.buffer().read(cx);
18712        for range in ranges {
18713            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18714                buffers_affected.insert(buffer.read(cx).remote_id());
18715            };
18716        }
18717
18718        self.display_map.update(cx, update);
18719
18720        if auto_scroll {
18721            self.request_autoscroll(Autoscroll::fit(), cx);
18722        }
18723
18724        cx.notify();
18725        self.scrollbar_marker_state.dirty = true;
18726        self.active_indent_guides_state.dirty = true;
18727    }
18728
18729    pub fn update_renderer_widths(
18730        &mut self,
18731        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18732        cx: &mut Context<Self>,
18733    ) -> bool {
18734        self.display_map
18735            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18736    }
18737
18738    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18739        self.display_map.read(cx).fold_placeholder.clone()
18740    }
18741
18742    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18743        self.buffer.update(cx, |buffer, cx| {
18744            buffer.set_all_diff_hunks_expanded(cx);
18745        });
18746    }
18747
18748    pub fn expand_all_diff_hunks(
18749        &mut self,
18750        _: &ExpandAllDiffHunks,
18751        _window: &mut Window,
18752        cx: &mut Context<Self>,
18753    ) {
18754        self.buffer.update(cx, |buffer, cx| {
18755            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18756        });
18757    }
18758
18759    pub fn collapse_all_diff_hunks(
18760        &mut self,
18761        _: &CollapseAllDiffHunks,
18762        _window: &mut Window,
18763        cx: &mut Context<Self>,
18764    ) {
18765        self.buffer.update(cx, |buffer, cx| {
18766            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18767        });
18768    }
18769
18770    pub fn toggle_selected_diff_hunks(
18771        &mut self,
18772        _: &ToggleSelectedDiffHunks,
18773        _window: &mut Window,
18774        cx: &mut Context<Self>,
18775    ) {
18776        let ranges: Vec<_> = self
18777            .selections
18778            .disjoint_anchors()
18779            .iter()
18780            .map(|s| s.range())
18781            .collect();
18782        self.toggle_diff_hunks_in_ranges(ranges, cx);
18783    }
18784
18785    pub fn diff_hunks_in_ranges<'a>(
18786        &'a self,
18787        ranges: &'a [Range<Anchor>],
18788        buffer: &'a MultiBufferSnapshot,
18789    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18790        ranges.iter().flat_map(move |range| {
18791            let end_excerpt_id = range.end.excerpt_id;
18792            let range = range.to_point(buffer);
18793            let mut peek_end = range.end;
18794            if range.end.row < buffer.max_row().0 {
18795                peek_end = Point::new(range.end.row + 1, 0);
18796            }
18797            buffer
18798                .diff_hunks_in_range(range.start..peek_end)
18799                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18800        })
18801    }
18802
18803    pub fn has_stageable_diff_hunks_in_ranges(
18804        &self,
18805        ranges: &[Range<Anchor>],
18806        snapshot: &MultiBufferSnapshot,
18807    ) -> bool {
18808        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18809        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18810    }
18811
18812    pub fn toggle_staged_selected_diff_hunks(
18813        &mut self,
18814        _: &::git::ToggleStaged,
18815        _: &mut Window,
18816        cx: &mut Context<Self>,
18817    ) {
18818        let snapshot = self.buffer.read(cx).snapshot(cx);
18819        let ranges: Vec<_> = self
18820            .selections
18821            .disjoint_anchors()
18822            .iter()
18823            .map(|s| s.range())
18824            .collect();
18825        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18826        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18827    }
18828
18829    pub fn set_render_diff_hunk_controls(
18830        &mut self,
18831        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18832        cx: &mut Context<Self>,
18833    ) {
18834        self.render_diff_hunk_controls = render_diff_hunk_controls;
18835        cx.notify();
18836    }
18837
18838    pub fn stage_and_next(
18839        &mut self,
18840        _: &::git::StageAndNext,
18841        window: &mut Window,
18842        cx: &mut Context<Self>,
18843    ) {
18844        self.do_stage_or_unstage_and_next(true, window, cx);
18845    }
18846
18847    pub fn unstage_and_next(
18848        &mut self,
18849        _: &::git::UnstageAndNext,
18850        window: &mut Window,
18851        cx: &mut Context<Self>,
18852    ) {
18853        self.do_stage_or_unstage_and_next(false, window, cx);
18854    }
18855
18856    pub fn stage_or_unstage_diff_hunks(
18857        &mut self,
18858        stage: bool,
18859        ranges: Vec<Range<Anchor>>,
18860        cx: &mut Context<Self>,
18861    ) {
18862        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18863        cx.spawn(async move |this, cx| {
18864            task.await?;
18865            this.update(cx, |this, cx| {
18866                let snapshot = this.buffer.read(cx).snapshot(cx);
18867                let chunk_by = this
18868                    .diff_hunks_in_ranges(&ranges, &snapshot)
18869                    .chunk_by(|hunk| hunk.buffer_id);
18870                for (buffer_id, hunks) in &chunk_by {
18871                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18872                }
18873            })
18874        })
18875        .detach_and_log_err(cx);
18876    }
18877
18878    fn save_buffers_for_ranges_if_needed(
18879        &mut self,
18880        ranges: &[Range<Anchor>],
18881        cx: &mut Context<Editor>,
18882    ) -> Task<Result<()>> {
18883        let multibuffer = self.buffer.read(cx);
18884        let snapshot = multibuffer.read(cx);
18885        let buffer_ids: HashSet<_> = ranges
18886            .iter()
18887            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18888            .collect();
18889        drop(snapshot);
18890
18891        let mut buffers = HashSet::default();
18892        for buffer_id in buffer_ids {
18893            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18894                let buffer = buffer_entity.read(cx);
18895                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18896                {
18897                    buffers.insert(buffer_entity);
18898                }
18899            }
18900        }
18901
18902        if let Some(project) = &self.project {
18903            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18904        } else {
18905            Task::ready(Ok(()))
18906        }
18907    }
18908
18909    fn do_stage_or_unstage_and_next(
18910        &mut self,
18911        stage: bool,
18912        window: &mut Window,
18913        cx: &mut Context<Self>,
18914    ) {
18915        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18916
18917        if ranges.iter().any(|range| range.start != range.end) {
18918            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18919            return;
18920        }
18921
18922        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18923        let snapshot = self.snapshot(window, cx);
18924        let position = self
18925            .selections
18926            .newest::<Point>(&snapshot.display_snapshot)
18927            .head();
18928        let mut row = snapshot
18929            .buffer_snapshot()
18930            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18931            .find(|hunk| hunk.row_range.start.0 > position.row)
18932            .map(|hunk| hunk.row_range.start);
18933
18934        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18935        // Outside of the project diff editor, wrap around to the beginning.
18936        if !all_diff_hunks_expanded {
18937            row = row.or_else(|| {
18938                snapshot
18939                    .buffer_snapshot()
18940                    .diff_hunks_in_range(Point::zero()..position)
18941                    .find(|hunk| hunk.row_range.end.0 < position.row)
18942                    .map(|hunk| hunk.row_range.start)
18943            });
18944        }
18945
18946        if let Some(row) = row {
18947            let destination = Point::new(row.0, 0);
18948            let autoscroll = Autoscroll::center();
18949
18950            self.unfold_ranges(&[destination..destination], false, false, cx);
18951            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18952                s.select_ranges([destination..destination]);
18953            });
18954        }
18955    }
18956
18957    fn do_stage_or_unstage(
18958        &self,
18959        stage: bool,
18960        buffer_id: BufferId,
18961        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18962        cx: &mut App,
18963    ) -> Option<()> {
18964        let project = self.project()?;
18965        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18966        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18967        let buffer_snapshot = buffer.read(cx).snapshot();
18968        let file_exists = buffer_snapshot
18969            .file()
18970            .is_some_and(|file| file.disk_state().exists());
18971        diff.update(cx, |diff, cx| {
18972            diff.stage_or_unstage_hunks(
18973                stage,
18974                &hunks
18975                    .map(|hunk| buffer_diff::DiffHunk {
18976                        buffer_range: hunk.buffer_range,
18977                        diff_base_byte_range: hunk.diff_base_byte_range,
18978                        secondary_status: hunk.secondary_status,
18979                        range: Point::zero()..Point::zero(), // unused
18980                    })
18981                    .collect::<Vec<_>>(),
18982                &buffer_snapshot,
18983                file_exists,
18984                cx,
18985            )
18986        });
18987        None
18988    }
18989
18990    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18991        let ranges: Vec<_> = self
18992            .selections
18993            .disjoint_anchors()
18994            .iter()
18995            .map(|s| s.range())
18996            .collect();
18997        self.buffer
18998            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18999    }
19000
19001    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19002        self.buffer.update(cx, |buffer, cx| {
19003            let ranges = vec![Anchor::min()..Anchor::max()];
19004            if !buffer.all_diff_hunks_expanded()
19005                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19006            {
19007                buffer.collapse_diff_hunks(ranges, cx);
19008                true
19009            } else {
19010                false
19011            }
19012        })
19013    }
19014
19015    fn toggle_diff_hunks_in_ranges(
19016        &mut self,
19017        ranges: Vec<Range<Anchor>>,
19018        cx: &mut Context<Editor>,
19019    ) {
19020        self.buffer.update(cx, |buffer, cx| {
19021            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19022            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19023        })
19024    }
19025
19026    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19027        self.buffer.update(cx, |buffer, cx| {
19028            let snapshot = buffer.snapshot(cx);
19029            let excerpt_id = range.end.excerpt_id;
19030            let point_range = range.to_point(&snapshot);
19031            let expand = !buffer.single_hunk_is_expanded(range, cx);
19032            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19033        })
19034    }
19035
19036    pub(crate) fn apply_all_diff_hunks(
19037        &mut self,
19038        _: &ApplyAllDiffHunks,
19039        window: &mut Window,
19040        cx: &mut Context<Self>,
19041    ) {
19042        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19043
19044        let buffers = self.buffer.read(cx).all_buffers();
19045        for branch_buffer in buffers {
19046            branch_buffer.update(cx, |branch_buffer, cx| {
19047                branch_buffer.merge_into_base(Vec::new(), cx);
19048            });
19049        }
19050
19051        if let Some(project) = self.project.clone() {
19052            self.save(
19053                SaveOptions {
19054                    format: true,
19055                    autosave: false,
19056                },
19057                project,
19058                window,
19059                cx,
19060            )
19061            .detach_and_log_err(cx);
19062        }
19063    }
19064
19065    pub(crate) fn apply_selected_diff_hunks(
19066        &mut self,
19067        _: &ApplyDiffHunk,
19068        window: &mut Window,
19069        cx: &mut Context<Self>,
19070    ) {
19071        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19072        let snapshot = self.snapshot(window, cx);
19073        let hunks = snapshot.hunks_for_ranges(
19074            self.selections
19075                .all(&snapshot.display_snapshot)
19076                .into_iter()
19077                .map(|selection| selection.range()),
19078        );
19079        let mut ranges_by_buffer = HashMap::default();
19080        self.transact(window, cx, |editor, _window, cx| {
19081            for hunk in hunks {
19082                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19083                    ranges_by_buffer
19084                        .entry(buffer.clone())
19085                        .or_insert_with(Vec::new)
19086                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19087                }
19088            }
19089
19090            for (buffer, ranges) in ranges_by_buffer {
19091                buffer.update(cx, |buffer, cx| {
19092                    buffer.merge_into_base(ranges, cx);
19093                });
19094            }
19095        });
19096
19097        if let Some(project) = self.project.clone() {
19098            self.save(
19099                SaveOptions {
19100                    format: true,
19101                    autosave: false,
19102                },
19103                project,
19104                window,
19105                cx,
19106            )
19107            .detach_and_log_err(cx);
19108        }
19109    }
19110
19111    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19112        if hovered != self.gutter_hovered {
19113            self.gutter_hovered = hovered;
19114            cx.notify();
19115        }
19116    }
19117
19118    pub fn insert_blocks(
19119        &mut self,
19120        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19121        autoscroll: Option<Autoscroll>,
19122        cx: &mut Context<Self>,
19123    ) -> Vec<CustomBlockId> {
19124        let blocks = self
19125            .display_map
19126            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19127        if let Some(autoscroll) = autoscroll {
19128            self.request_autoscroll(autoscroll, cx);
19129        }
19130        cx.notify();
19131        blocks
19132    }
19133
19134    pub fn resize_blocks(
19135        &mut self,
19136        heights: HashMap<CustomBlockId, u32>,
19137        autoscroll: Option<Autoscroll>,
19138        cx: &mut Context<Self>,
19139    ) {
19140        self.display_map
19141            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19142        if let Some(autoscroll) = autoscroll {
19143            self.request_autoscroll(autoscroll, cx);
19144        }
19145        cx.notify();
19146    }
19147
19148    pub fn replace_blocks(
19149        &mut self,
19150        renderers: HashMap<CustomBlockId, RenderBlock>,
19151        autoscroll: Option<Autoscroll>,
19152        cx: &mut Context<Self>,
19153    ) {
19154        self.display_map
19155            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19156        if let Some(autoscroll) = autoscroll {
19157            self.request_autoscroll(autoscroll, cx);
19158        }
19159        cx.notify();
19160    }
19161
19162    pub fn remove_blocks(
19163        &mut self,
19164        block_ids: HashSet<CustomBlockId>,
19165        autoscroll: Option<Autoscroll>,
19166        cx: &mut Context<Self>,
19167    ) {
19168        self.display_map.update(cx, |display_map, cx| {
19169            display_map.remove_blocks(block_ids, cx)
19170        });
19171        if let Some(autoscroll) = autoscroll {
19172            self.request_autoscroll(autoscroll, cx);
19173        }
19174        cx.notify();
19175    }
19176
19177    pub fn row_for_block(
19178        &self,
19179        block_id: CustomBlockId,
19180        cx: &mut Context<Self>,
19181    ) -> Option<DisplayRow> {
19182        self.display_map
19183            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19184    }
19185
19186    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19187        self.focused_block = Some(focused_block);
19188    }
19189
19190    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19191        self.focused_block.take()
19192    }
19193
19194    pub fn insert_creases(
19195        &mut self,
19196        creases: impl IntoIterator<Item = Crease<Anchor>>,
19197        cx: &mut Context<Self>,
19198    ) -> Vec<CreaseId> {
19199        self.display_map
19200            .update(cx, |map, cx| map.insert_creases(creases, cx))
19201    }
19202
19203    pub fn remove_creases(
19204        &mut self,
19205        ids: impl IntoIterator<Item = CreaseId>,
19206        cx: &mut Context<Self>,
19207    ) -> Vec<(CreaseId, Range<Anchor>)> {
19208        self.display_map
19209            .update(cx, |map, cx| map.remove_creases(ids, cx))
19210    }
19211
19212    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19213        self.display_map
19214            .update(cx, |map, cx| map.snapshot(cx))
19215            .longest_row()
19216    }
19217
19218    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19219        self.display_map
19220            .update(cx, |map, cx| map.snapshot(cx))
19221            .max_point()
19222    }
19223
19224    pub fn text(&self, cx: &App) -> String {
19225        self.buffer.read(cx).read(cx).text()
19226    }
19227
19228    pub fn is_empty(&self, cx: &App) -> bool {
19229        self.buffer.read(cx).read(cx).is_empty()
19230    }
19231
19232    pub fn text_option(&self, cx: &App) -> Option<String> {
19233        let text = self.text(cx);
19234        let text = text.trim();
19235
19236        if text.is_empty() {
19237            return None;
19238        }
19239
19240        Some(text.to_string())
19241    }
19242
19243    pub fn set_text(
19244        &mut self,
19245        text: impl Into<Arc<str>>,
19246        window: &mut Window,
19247        cx: &mut Context<Self>,
19248    ) {
19249        self.transact(window, cx, |this, _, cx| {
19250            this.buffer
19251                .read(cx)
19252                .as_singleton()
19253                .expect("you can only call set_text on editors for singleton buffers")
19254                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19255        });
19256    }
19257
19258    pub fn display_text(&self, cx: &mut App) -> String {
19259        self.display_map
19260            .update(cx, |map, cx| map.snapshot(cx))
19261            .text()
19262    }
19263
19264    fn create_minimap(
19265        &self,
19266        minimap_settings: MinimapSettings,
19267        window: &mut Window,
19268        cx: &mut Context<Self>,
19269    ) -> Option<Entity<Self>> {
19270        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19271            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19272    }
19273
19274    fn initialize_new_minimap(
19275        &self,
19276        minimap_settings: MinimapSettings,
19277        window: &mut Window,
19278        cx: &mut Context<Self>,
19279    ) -> Entity<Self> {
19280        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19281
19282        let mut minimap = Editor::new_internal(
19283            EditorMode::Minimap {
19284                parent: cx.weak_entity(),
19285            },
19286            self.buffer.clone(),
19287            None,
19288            Some(self.display_map.clone()),
19289            window,
19290            cx,
19291        );
19292        minimap.scroll_manager.clone_state(&self.scroll_manager);
19293        minimap.set_text_style_refinement(TextStyleRefinement {
19294            font_size: Some(MINIMAP_FONT_SIZE),
19295            font_weight: Some(MINIMAP_FONT_WEIGHT),
19296            ..Default::default()
19297        });
19298        minimap.update_minimap_configuration(minimap_settings, cx);
19299        cx.new(|_| minimap)
19300    }
19301
19302    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19303        let current_line_highlight = minimap_settings
19304            .current_line_highlight
19305            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19306        self.set_current_line_highlight(Some(current_line_highlight));
19307    }
19308
19309    pub fn minimap(&self) -> Option<&Entity<Self>> {
19310        self.minimap
19311            .as_ref()
19312            .filter(|_| self.minimap_visibility.visible())
19313    }
19314
19315    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19316        let mut wrap_guides = smallvec![];
19317
19318        if self.show_wrap_guides == Some(false) {
19319            return wrap_guides;
19320        }
19321
19322        let settings = self.buffer.read(cx).language_settings(cx);
19323        if settings.show_wrap_guides {
19324            match self.soft_wrap_mode(cx) {
19325                SoftWrap::Column(soft_wrap) => {
19326                    wrap_guides.push((soft_wrap as usize, true));
19327                }
19328                SoftWrap::Bounded(soft_wrap) => {
19329                    wrap_guides.push((soft_wrap as usize, true));
19330                }
19331                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19332            }
19333            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19334        }
19335
19336        wrap_guides
19337    }
19338
19339    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19340        let settings = self.buffer.read(cx).language_settings(cx);
19341        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19342        match mode {
19343            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19344                SoftWrap::None
19345            }
19346            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19347            language_settings::SoftWrap::PreferredLineLength => {
19348                SoftWrap::Column(settings.preferred_line_length)
19349            }
19350            language_settings::SoftWrap::Bounded => {
19351                SoftWrap::Bounded(settings.preferred_line_length)
19352            }
19353        }
19354    }
19355
19356    pub fn set_soft_wrap_mode(
19357        &mut self,
19358        mode: language_settings::SoftWrap,
19359
19360        cx: &mut Context<Self>,
19361    ) {
19362        self.soft_wrap_mode_override = Some(mode);
19363        cx.notify();
19364    }
19365
19366    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19367        self.hard_wrap = hard_wrap;
19368        cx.notify();
19369    }
19370
19371    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19372        self.text_style_refinement = Some(style);
19373    }
19374
19375    /// called by the Element so we know what style we were most recently rendered with.
19376    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19377        // We intentionally do not inform the display map about the minimap style
19378        // so that wrapping is not recalculated and stays consistent for the editor
19379        // and its linked minimap.
19380        if !self.mode.is_minimap() {
19381            let font = style.text.font();
19382            let font_size = style.text.font_size.to_pixels(window.rem_size());
19383            let display_map = self
19384                .placeholder_display_map
19385                .as_ref()
19386                .filter(|_| self.is_empty(cx))
19387                .unwrap_or(&self.display_map);
19388
19389            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19390        }
19391        self.style = Some(style);
19392    }
19393
19394    pub fn style(&self) -> Option<&EditorStyle> {
19395        self.style.as_ref()
19396    }
19397
19398    // Called by the element. This method is not designed to be called outside of the editor
19399    // element's layout code because it does not notify when rewrapping is computed synchronously.
19400    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19401        if self.is_empty(cx) {
19402            self.placeholder_display_map
19403                .as_ref()
19404                .map_or(false, |display_map| {
19405                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19406                })
19407        } else {
19408            self.display_map
19409                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19410        }
19411    }
19412
19413    pub fn set_soft_wrap(&mut self) {
19414        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19415    }
19416
19417    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19418        if self.soft_wrap_mode_override.is_some() {
19419            self.soft_wrap_mode_override.take();
19420        } else {
19421            let soft_wrap = match self.soft_wrap_mode(cx) {
19422                SoftWrap::GitDiff => return,
19423                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19424                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19425                    language_settings::SoftWrap::None
19426                }
19427            };
19428            self.soft_wrap_mode_override = Some(soft_wrap);
19429        }
19430        cx.notify();
19431    }
19432
19433    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19434        let Some(workspace) = self.workspace() else {
19435            return;
19436        };
19437        let fs = workspace.read(cx).app_state().fs.clone();
19438        let current_show = TabBarSettings::get_global(cx).show;
19439        update_settings_file(fs, cx, move |setting, _| {
19440            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19441        });
19442    }
19443
19444    pub fn toggle_indent_guides(
19445        &mut self,
19446        _: &ToggleIndentGuides,
19447        _: &mut Window,
19448        cx: &mut Context<Self>,
19449    ) {
19450        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19451            self.buffer
19452                .read(cx)
19453                .language_settings(cx)
19454                .indent_guides
19455                .enabled
19456        });
19457        self.show_indent_guides = Some(!currently_enabled);
19458        cx.notify();
19459    }
19460
19461    fn should_show_indent_guides(&self) -> Option<bool> {
19462        self.show_indent_guides
19463    }
19464
19465    pub fn toggle_line_numbers(
19466        &mut self,
19467        _: &ToggleLineNumbers,
19468        _: &mut Window,
19469        cx: &mut Context<Self>,
19470    ) {
19471        let mut editor_settings = EditorSettings::get_global(cx).clone();
19472        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19473        EditorSettings::override_global(editor_settings, cx);
19474    }
19475
19476    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19477        if let Some(show_line_numbers) = self.show_line_numbers {
19478            return show_line_numbers;
19479        }
19480        EditorSettings::get_global(cx).gutter.line_numbers
19481    }
19482
19483    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19484        self.use_relative_line_numbers
19485            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19486    }
19487
19488    pub fn toggle_relative_line_numbers(
19489        &mut self,
19490        _: &ToggleRelativeLineNumbers,
19491        _: &mut Window,
19492        cx: &mut Context<Self>,
19493    ) {
19494        let is_relative = self.should_use_relative_line_numbers(cx);
19495        self.set_relative_line_number(Some(!is_relative), cx)
19496    }
19497
19498    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19499        self.use_relative_line_numbers = is_relative;
19500        cx.notify();
19501    }
19502
19503    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19504        self.show_gutter = show_gutter;
19505        cx.notify();
19506    }
19507
19508    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19509        self.show_scrollbars = ScrollbarAxes {
19510            horizontal: show,
19511            vertical: show,
19512        };
19513        cx.notify();
19514    }
19515
19516    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19517        self.show_scrollbars.vertical = show;
19518        cx.notify();
19519    }
19520
19521    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19522        self.show_scrollbars.horizontal = show;
19523        cx.notify();
19524    }
19525
19526    pub fn set_minimap_visibility(
19527        &mut self,
19528        minimap_visibility: MinimapVisibility,
19529        window: &mut Window,
19530        cx: &mut Context<Self>,
19531    ) {
19532        if self.minimap_visibility != minimap_visibility {
19533            if minimap_visibility.visible() && self.minimap.is_none() {
19534                let minimap_settings = EditorSettings::get_global(cx).minimap;
19535                self.minimap =
19536                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19537            }
19538            self.minimap_visibility = minimap_visibility;
19539            cx.notify();
19540        }
19541    }
19542
19543    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19544        self.set_show_scrollbars(false, cx);
19545        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19546    }
19547
19548    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19549        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19550    }
19551
19552    /// Normally the text in full mode and auto height editors is padded on the
19553    /// left side by roughly half a character width for improved hit testing.
19554    ///
19555    /// Use this method to disable this for cases where this is not wanted (e.g.
19556    /// if you want to align the editor text with some other text above or below)
19557    /// or if you want to add this padding to single-line editors.
19558    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19559        self.offset_content = offset_content;
19560        cx.notify();
19561    }
19562
19563    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19564        self.show_line_numbers = Some(show_line_numbers);
19565        cx.notify();
19566    }
19567
19568    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19569        self.disable_expand_excerpt_buttons = true;
19570        cx.notify();
19571    }
19572
19573    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19574        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19575        cx.notify();
19576    }
19577
19578    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19579        self.show_code_actions = Some(show_code_actions);
19580        cx.notify();
19581    }
19582
19583    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19584        self.show_runnables = Some(show_runnables);
19585        cx.notify();
19586    }
19587
19588    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19589        self.show_breakpoints = Some(show_breakpoints);
19590        cx.notify();
19591    }
19592
19593    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19594        if self.display_map.read(cx).masked != masked {
19595            self.display_map.update(cx, |map, _| map.masked = masked);
19596        }
19597        cx.notify()
19598    }
19599
19600    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19601        self.show_wrap_guides = Some(show_wrap_guides);
19602        cx.notify();
19603    }
19604
19605    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19606        self.show_indent_guides = Some(show_indent_guides);
19607        cx.notify();
19608    }
19609
19610    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19611        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19612            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19613                && let Some(dir) = file.abs_path(cx).parent()
19614            {
19615                return Some(dir.to_owned());
19616            }
19617        }
19618
19619        None
19620    }
19621
19622    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19623        self.active_excerpt(cx)?
19624            .1
19625            .read(cx)
19626            .file()
19627            .and_then(|f| f.as_local())
19628    }
19629
19630    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19631        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19632            let buffer = buffer.read(cx);
19633            if let Some(project_path) = buffer.project_path(cx) {
19634                let project = self.project()?.read(cx);
19635                project.absolute_path(&project_path, cx)
19636            } else {
19637                buffer
19638                    .file()
19639                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19640            }
19641        })
19642    }
19643
19644    pub fn reveal_in_finder(
19645        &mut self,
19646        _: &RevealInFileManager,
19647        _window: &mut Window,
19648        cx: &mut Context<Self>,
19649    ) {
19650        if let Some(target) = self.target_file(cx) {
19651            cx.reveal_path(&target.abs_path(cx));
19652        }
19653    }
19654
19655    pub fn copy_path(
19656        &mut self,
19657        _: &zed_actions::workspace::CopyPath,
19658        _window: &mut Window,
19659        cx: &mut Context<Self>,
19660    ) {
19661        if let Some(path) = self.target_file_abs_path(cx)
19662            && let Some(path) = path.to_str()
19663        {
19664            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19665        } else {
19666            cx.propagate();
19667        }
19668    }
19669
19670    pub fn copy_relative_path(
19671        &mut self,
19672        _: &zed_actions::workspace::CopyRelativePath,
19673        _window: &mut Window,
19674        cx: &mut Context<Self>,
19675    ) {
19676        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19677            let project = self.project()?.read(cx);
19678            let path = buffer.read(cx).file()?.path();
19679            let path = path.display(project.path_style(cx));
19680            Some(path)
19681        }) {
19682            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19683        } else {
19684            cx.propagate();
19685        }
19686    }
19687
19688    /// Returns the project path for the editor's buffer, if any buffer is
19689    /// opened in the editor.
19690    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19691        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19692            buffer.read(cx).project_path(cx)
19693        } else {
19694            None
19695        }
19696    }
19697
19698    // Returns true if the editor handled a go-to-line request
19699    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19700        maybe!({
19701            let breakpoint_store = self.breakpoint_store.as_ref()?;
19702
19703            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19704            else {
19705                self.clear_row_highlights::<ActiveDebugLine>();
19706                return None;
19707            };
19708
19709            let position = active_stack_frame.position;
19710            let buffer_id = position.buffer_id?;
19711            let snapshot = self
19712                .project
19713                .as_ref()?
19714                .read(cx)
19715                .buffer_for_id(buffer_id, cx)?
19716                .read(cx)
19717                .snapshot();
19718
19719            let mut handled = false;
19720            for (id, ExcerptRange { context, .. }) in
19721                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19722            {
19723                if context.start.cmp(&position, &snapshot).is_ge()
19724                    || context.end.cmp(&position, &snapshot).is_lt()
19725                {
19726                    continue;
19727                }
19728                let snapshot = self.buffer.read(cx).snapshot(cx);
19729                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19730
19731                handled = true;
19732                self.clear_row_highlights::<ActiveDebugLine>();
19733
19734                self.go_to_line::<ActiveDebugLine>(
19735                    multibuffer_anchor,
19736                    Some(cx.theme().colors().editor_debugger_active_line_background),
19737                    window,
19738                    cx,
19739                );
19740
19741                cx.notify();
19742            }
19743
19744            handled.then_some(())
19745        })
19746        .is_some()
19747    }
19748
19749    pub fn copy_file_name_without_extension(
19750        &mut self,
19751        _: &CopyFileNameWithoutExtension,
19752        _: &mut Window,
19753        cx: &mut Context<Self>,
19754    ) {
19755        if let Some(file) = self.target_file(cx)
19756            && let Some(file_stem) = file.path().file_stem()
19757        {
19758            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19759        }
19760    }
19761
19762    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19763        if let Some(file) = self.target_file(cx)
19764            && let Some(name) = file.path().file_name()
19765        {
19766            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19767        }
19768    }
19769
19770    pub fn toggle_git_blame(
19771        &mut self,
19772        _: &::git::Blame,
19773        window: &mut Window,
19774        cx: &mut Context<Self>,
19775    ) {
19776        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19777
19778        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19779            self.start_git_blame(true, window, cx);
19780        }
19781
19782        cx.notify();
19783    }
19784
19785    pub fn toggle_git_blame_inline(
19786        &mut self,
19787        _: &ToggleGitBlameInline,
19788        window: &mut Window,
19789        cx: &mut Context<Self>,
19790    ) {
19791        self.toggle_git_blame_inline_internal(true, window, cx);
19792        cx.notify();
19793    }
19794
19795    pub fn open_git_blame_commit(
19796        &mut self,
19797        _: &OpenGitBlameCommit,
19798        window: &mut Window,
19799        cx: &mut Context<Self>,
19800    ) {
19801        self.open_git_blame_commit_internal(window, cx);
19802    }
19803
19804    fn open_git_blame_commit_internal(
19805        &mut self,
19806        window: &mut Window,
19807        cx: &mut Context<Self>,
19808    ) -> Option<()> {
19809        let blame = self.blame.as_ref()?;
19810        let snapshot = self.snapshot(window, cx);
19811        let cursor = self
19812            .selections
19813            .newest::<Point>(&snapshot.display_snapshot)
19814            .head();
19815        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19816        let (_, blame_entry) = blame
19817            .update(cx, |blame, cx| {
19818                blame
19819                    .blame_for_rows(
19820                        &[RowInfo {
19821                            buffer_id: Some(buffer.remote_id()),
19822                            buffer_row: Some(point.row),
19823                            ..Default::default()
19824                        }],
19825                        cx,
19826                    )
19827                    .next()
19828            })
19829            .flatten()?;
19830        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19831        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19832        let workspace = self.workspace()?.downgrade();
19833        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19834        None
19835    }
19836
19837    pub fn git_blame_inline_enabled(&self) -> bool {
19838        self.git_blame_inline_enabled
19839    }
19840
19841    pub fn toggle_selection_menu(
19842        &mut self,
19843        _: &ToggleSelectionMenu,
19844        _: &mut Window,
19845        cx: &mut Context<Self>,
19846    ) {
19847        self.show_selection_menu = self
19848            .show_selection_menu
19849            .map(|show_selections_menu| !show_selections_menu)
19850            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19851
19852        cx.notify();
19853    }
19854
19855    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19856        self.show_selection_menu
19857            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19858    }
19859
19860    fn start_git_blame(
19861        &mut self,
19862        user_triggered: bool,
19863        window: &mut Window,
19864        cx: &mut Context<Self>,
19865    ) {
19866        if let Some(project) = self.project() {
19867            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19868                && buffer.read(cx).file().is_none()
19869            {
19870                return;
19871            }
19872
19873            let focused = self.focus_handle(cx).contains_focused(window, cx);
19874
19875            let project = project.clone();
19876            let blame = cx
19877                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19878            self.blame_subscription =
19879                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19880            self.blame = Some(blame);
19881        }
19882    }
19883
19884    fn toggle_git_blame_inline_internal(
19885        &mut self,
19886        user_triggered: bool,
19887        window: &mut Window,
19888        cx: &mut Context<Self>,
19889    ) {
19890        if self.git_blame_inline_enabled {
19891            self.git_blame_inline_enabled = false;
19892            self.show_git_blame_inline = false;
19893            self.show_git_blame_inline_delay_task.take();
19894        } else {
19895            self.git_blame_inline_enabled = true;
19896            self.start_git_blame_inline(user_triggered, window, cx);
19897        }
19898
19899        cx.notify();
19900    }
19901
19902    fn start_git_blame_inline(
19903        &mut self,
19904        user_triggered: bool,
19905        window: &mut Window,
19906        cx: &mut Context<Self>,
19907    ) {
19908        self.start_git_blame(user_triggered, window, cx);
19909
19910        if ProjectSettings::get_global(cx)
19911            .git
19912            .inline_blame_delay()
19913            .is_some()
19914        {
19915            self.start_inline_blame_timer(window, cx);
19916        } else {
19917            self.show_git_blame_inline = true
19918        }
19919    }
19920
19921    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19922        self.blame.as_ref()
19923    }
19924
19925    pub fn show_git_blame_gutter(&self) -> bool {
19926        self.show_git_blame_gutter
19927    }
19928
19929    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19930        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19931    }
19932
19933    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19934        self.show_git_blame_inline
19935            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19936            && !self.newest_selection_head_on_empty_line(cx)
19937            && self.has_blame_entries(cx)
19938    }
19939
19940    fn has_blame_entries(&self, cx: &App) -> bool {
19941        self.blame()
19942            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19943    }
19944
19945    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19946        let cursor_anchor = self.selections.newest_anchor().head();
19947
19948        let snapshot = self.buffer.read(cx).snapshot(cx);
19949        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19950
19951        snapshot.line_len(buffer_row) == 0
19952    }
19953
19954    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19955        let buffer_and_selection = maybe!({
19956            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19957            let selection_range = selection.range();
19958
19959            let multi_buffer = self.buffer().read(cx);
19960            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19961            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19962
19963            let (buffer, range, _) = if selection.reversed {
19964                buffer_ranges.first()
19965            } else {
19966                buffer_ranges.last()
19967            }?;
19968
19969            let selection = text::ToPoint::to_point(&range.start, buffer).row
19970                ..text::ToPoint::to_point(&range.end, buffer).row;
19971            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19972        });
19973
19974        let Some((buffer, selection)) = buffer_and_selection else {
19975            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19976        };
19977
19978        let Some(project) = self.project() else {
19979            return Task::ready(Err(anyhow!("editor does not have project")));
19980        };
19981
19982        project.update(cx, |project, cx| {
19983            project.get_permalink_to_line(&buffer, selection, cx)
19984        })
19985    }
19986
19987    pub fn copy_permalink_to_line(
19988        &mut self,
19989        _: &CopyPermalinkToLine,
19990        window: &mut Window,
19991        cx: &mut Context<Self>,
19992    ) {
19993        let permalink_task = self.get_permalink_to_line(cx);
19994        let workspace = self.workspace();
19995
19996        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19997            Ok(permalink) => {
19998                cx.update(|_, cx| {
19999                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20000                })
20001                .ok();
20002            }
20003            Err(err) => {
20004                let message = format!("Failed to copy permalink: {err}");
20005
20006                anyhow::Result::<()>::Err(err).log_err();
20007
20008                if let Some(workspace) = workspace {
20009                    workspace
20010                        .update_in(cx, |workspace, _, cx| {
20011                            struct CopyPermalinkToLine;
20012
20013                            workspace.show_toast(
20014                                Toast::new(
20015                                    NotificationId::unique::<CopyPermalinkToLine>(),
20016                                    message,
20017                                ),
20018                                cx,
20019                            )
20020                        })
20021                        .ok();
20022                }
20023            }
20024        })
20025        .detach();
20026    }
20027
20028    pub fn copy_file_location(
20029        &mut self,
20030        _: &CopyFileLocation,
20031        _: &mut Window,
20032        cx: &mut Context<Self>,
20033    ) {
20034        let selection = self
20035            .selections
20036            .newest::<Point>(&self.display_snapshot(cx))
20037            .start
20038            .row
20039            + 1;
20040        if let Some(file) = self.target_file(cx) {
20041            let path = file.path().display(file.path_style(cx));
20042            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20043        }
20044    }
20045
20046    pub fn open_permalink_to_line(
20047        &mut self,
20048        _: &OpenPermalinkToLine,
20049        window: &mut Window,
20050        cx: &mut Context<Self>,
20051    ) {
20052        let permalink_task = self.get_permalink_to_line(cx);
20053        let workspace = self.workspace();
20054
20055        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20056            Ok(permalink) => {
20057                cx.update(|_, cx| {
20058                    cx.open_url(permalink.as_ref());
20059                })
20060                .ok();
20061            }
20062            Err(err) => {
20063                let message = format!("Failed to open permalink: {err}");
20064
20065                anyhow::Result::<()>::Err(err).log_err();
20066
20067                if let Some(workspace) = workspace {
20068                    workspace
20069                        .update(cx, |workspace, cx| {
20070                            struct OpenPermalinkToLine;
20071
20072                            workspace.show_toast(
20073                                Toast::new(
20074                                    NotificationId::unique::<OpenPermalinkToLine>(),
20075                                    message,
20076                                ),
20077                                cx,
20078                            )
20079                        })
20080                        .ok();
20081                }
20082            }
20083        })
20084        .detach();
20085    }
20086
20087    pub fn insert_uuid_v4(
20088        &mut self,
20089        _: &InsertUuidV4,
20090        window: &mut Window,
20091        cx: &mut Context<Self>,
20092    ) {
20093        self.insert_uuid(UuidVersion::V4, window, cx);
20094    }
20095
20096    pub fn insert_uuid_v7(
20097        &mut self,
20098        _: &InsertUuidV7,
20099        window: &mut Window,
20100        cx: &mut Context<Self>,
20101    ) {
20102        self.insert_uuid(UuidVersion::V7, window, cx);
20103    }
20104
20105    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20106        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20107        self.transact(window, cx, |this, window, cx| {
20108            let edits = this
20109                .selections
20110                .all::<Point>(&this.display_snapshot(cx))
20111                .into_iter()
20112                .map(|selection| {
20113                    let uuid = match version {
20114                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20115                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20116                    };
20117
20118                    (selection.range(), uuid.to_string())
20119                });
20120            this.edit(edits, cx);
20121            this.refresh_edit_prediction(true, false, window, cx);
20122        });
20123    }
20124
20125    pub fn open_selections_in_multibuffer(
20126        &mut self,
20127        _: &OpenSelectionsInMultibuffer,
20128        window: &mut Window,
20129        cx: &mut Context<Self>,
20130    ) {
20131        let multibuffer = self.buffer.read(cx);
20132
20133        let Some(buffer) = multibuffer.as_singleton() else {
20134            return;
20135        };
20136
20137        let Some(workspace) = self.workspace() else {
20138            return;
20139        };
20140
20141        let title = multibuffer.title(cx).to_string();
20142
20143        let locations = self
20144            .selections
20145            .all_anchors(cx)
20146            .iter()
20147            .map(|selection| {
20148                (
20149                    buffer.clone(),
20150                    (selection.start.text_anchor..selection.end.text_anchor)
20151                        .to_point(buffer.read(cx)),
20152                )
20153            })
20154            .into_group_map();
20155
20156        cx.spawn_in(window, async move |_, cx| {
20157            workspace.update_in(cx, |workspace, window, cx| {
20158                Self::open_locations_in_multibuffer(
20159                    workspace,
20160                    locations,
20161                    format!("Selections for '{title}'"),
20162                    false,
20163                    MultibufferSelectionMode::All,
20164                    window,
20165                    cx,
20166                );
20167            })
20168        })
20169        .detach();
20170    }
20171
20172    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20173    /// last highlight added will be used.
20174    ///
20175    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20176    pub fn highlight_rows<T: 'static>(
20177        &mut self,
20178        range: Range<Anchor>,
20179        color: Hsla,
20180        options: RowHighlightOptions,
20181        cx: &mut Context<Self>,
20182    ) {
20183        let snapshot = self.buffer().read(cx).snapshot(cx);
20184        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20185        let ix = row_highlights.binary_search_by(|highlight| {
20186            Ordering::Equal
20187                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20188                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20189        });
20190
20191        if let Err(mut ix) = ix {
20192            let index = post_inc(&mut self.highlight_order);
20193
20194            // If this range intersects with the preceding highlight, then merge it with
20195            // the preceding highlight. Otherwise insert a new highlight.
20196            let mut merged = false;
20197            if ix > 0 {
20198                let prev_highlight = &mut row_highlights[ix - 1];
20199                if prev_highlight
20200                    .range
20201                    .end
20202                    .cmp(&range.start, &snapshot)
20203                    .is_ge()
20204                {
20205                    ix -= 1;
20206                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20207                        prev_highlight.range.end = range.end;
20208                    }
20209                    merged = true;
20210                    prev_highlight.index = index;
20211                    prev_highlight.color = color;
20212                    prev_highlight.options = options;
20213                }
20214            }
20215
20216            if !merged {
20217                row_highlights.insert(
20218                    ix,
20219                    RowHighlight {
20220                        range,
20221                        index,
20222                        color,
20223                        options,
20224                        type_id: TypeId::of::<T>(),
20225                    },
20226                );
20227            }
20228
20229            // If any of the following highlights intersect with this one, merge them.
20230            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20231                let highlight = &row_highlights[ix];
20232                if next_highlight
20233                    .range
20234                    .start
20235                    .cmp(&highlight.range.end, &snapshot)
20236                    .is_le()
20237                {
20238                    if next_highlight
20239                        .range
20240                        .end
20241                        .cmp(&highlight.range.end, &snapshot)
20242                        .is_gt()
20243                    {
20244                        row_highlights[ix].range.end = next_highlight.range.end;
20245                    }
20246                    row_highlights.remove(ix + 1);
20247                } else {
20248                    break;
20249                }
20250            }
20251        }
20252    }
20253
20254    /// Remove any highlighted row ranges of the given type that intersect the
20255    /// given ranges.
20256    pub fn remove_highlighted_rows<T: 'static>(
20257        &mut self,
20258        ranges_to_remove: Vec<Range<Anchor>>,
20259        cx: &mut Context<Self>,
20260    ) {
20261        let snapshot = self.buffer().read(cx).snapshot(cx);
20262        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20263        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20264        row_highlights.retain(|highlight| {
20265            while let Some(range_to_remove) = ranges_to_remove.peek() {
20266                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20267                    Ordering::Less | Ordering::Equal => {
20268                        ranges_to_remove.next();
20269                    }
20270                    Ordering::Greater => {
20271                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20272                            Ordering::Less | Ordering::Equal => {
20273                                return false;
20274                            }
20275                            Ordering::Greater => break,
20276                        }
20277                    }
20278                }
20279            }
20280
20281            true
20282        })
20283    }
20284
20285    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20286    pub fn clear_row_highlights<T: 'static>(&mut self) {
20287        self.highlighted_rows.remove(&TypeId::of::<T>());
20288    }
20289
20290    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20291    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20292        self.highlighted_rows
20293            .get(&TypeId::of::<T>())
20294            .map_or(&[] as &[_], |vec| vec.as_slice())
20295            .iter()
20296            .map(|highlight| (highlight.range.clone(), highlight.color))
20297    }
20298
20299    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20300    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20301    /// Allows to ignore certain kinds of highlights.
20302    pub fn highlighted_display_rows(
20303        &self,
20304        window: &mut Window,
20305        cx: &mut App,
20306    ) -> BTreeMap<DisplayRow, LineHighlight> {
20307        let snapshot = self.snapshot(window, cx);
20308        let mut used_highlight_orders = HashMap::default();
20309        self.highlighted_rows
20310            .iter()
20311            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20312            .fold(
20313                BTreeMap::<DisplayRow, LineHighlight>::new(),
20314                |mut unique_rows, highlight| {
20315                    let start = highlight.range.start.to_display_point(&snapshot);
20316                    let end = highlight.range.end.to_display_point(&snapshot);
20317                    let start_row = start.row().0;
20318                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20319                        && end.column() == 0
20320                    {
20321                        end.row().0.saturating_sub(1)
20322                    } else {
20323                        end.row().0
20324                    };
20325                    for row in start_row..=end_row {
20326                        let used_index =
20327                            used_highlight_orders.entry(row).or_insert(highlight.index);
20328                        if highlight.index >= *used_index {
20329                            *used_index = highlight.index;
20330                            unique_rows.insert(
20331                                DisplayRow(row),
20332                                LineHighlight {
20333                                    include_gutter: highlight.options.include_gutter,
20334                                    border: None,
20335                                    background: highlight.color.into(),
20336                                    type_id: Some(highlight.type_id),
20337                                },
20338                            );
20339                        }
20340                    }
20341                    unique_rows
20342                },
20343            )
20344    }
20345
20346    pub fn highlighted_display_row_for_autoscroll(
20347        &self,
20348        snapshot: &DisplaySnapshot,
20349    ) -> Option<DisplayRow> {
20350        self.highlighted_rows
20351            .values()
20352            .flat_map(|highlighted_rows| highlighted_rows.iter())
20353            .filter_map(|highlight| {
20354                if highlight.options.autoscroll {
20355                    Some(highlight.range.start.to_display_point(snapshot).row())
20356                } else {
20357                    None
20358                }
20359            })
20360            .min()
20361    }
20362
20363    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20364        self.highlight_background::<SearchWithinRange>(
20365            ranges,
20366            |colors| colors.colors().editor_document_highlight_read_background,
20367            cx,
20368        )
20369    }
20370
20371    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20372        self.breadcrumb_header = Some(new_header);
20373    }
20374
20375    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20376        self.clear_background_highlights::<SearchWithinRange>(cx);
20377    }
20378
20379    pub fn highlight_background<T: 'static>(
20380        &mut self,
20381        ranges: &[Range<Anchor>],
20382        color_fetcher: fn(&Theme) -> Hsla,
20383        cx: &mut Context<Self>,
20384    ) {
20385        self.background_highlights.insert(
20386            HighlightKey::Type(TypeId::of::<T>()),
20387            (color_fetcher, Arc::from(ranges)),
20388        );
20389        self.scrollbar_marker_state.dirty = true;
20390        cx.notify();
20391    }
20392
20393    pub fn highlight_background_key<T: 'static>(
20394        &mut self,
20395        key: usize,
20396        ranges: &[Range<Anchor>],
20397        color_fetcher: fn(&Theme) -> Hsla,
20398        cx: &mut Context<Self>,
20399    ) {
20400        self.background_highlights.insert(
20401            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20402            (color_fetcher, Arc::from(ranges)),
20403        );
20404        self.scrollbar_marker_state.dirty = true;
20405        cx.notify();
20406    }
20407
20408    pub fn clear_background_highlights<T: 'static>(
20409        &mut self,
20410        cx: &mut Context<Self>,
20411    ) -> Option<BackgroundHighlight> {
20412        let text_highlights = self
20413            .background_highlights
20414            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20415        if !text_highlights.1.is_empty() {
20416            self.scrollbar_marker_state.dirty = true;
20417            cx.notify();
20418        }
20419        Some(text_highlights)
20420    }
20421
20422    pub fn highlight_gutter<T: 'static>(
20423        &mut self,
20424        ranges: impl Into<Vec<Range<Anchor>>>,
20425        color_fetcher: fn(&App) -> Hsla,
20426        cx: &mut Context<Self>,
20427    ) {
20428        self.gutter_highlights
20429            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20430        cx.notify();
20431    }
20432
20433    pub fn clear_gutter_highlights<T: 'static>(
20434        &mut self,
20435        cx: &mut Context<Self>,
20436    ) -> Option<GutterHighlight> {
20437        cx.notify();
20438        self.gutter_highlights.remove(&TypeId::of::<T>())
20439    }
20440
20441    pub fn insert_gutter_highlight<T: 'static>(
20442        &mut self,
20443        range: Range<Anchor>,
20444        color_fetcher: fn(&App) -> Hsla,
20445        cx: &mut Context<Self>,
20446    ) {
20447        let snapshot = self.buffer().read(cx).snapshot(cx);
20448        let mut highlights = self
20449            .gutter_highlights
20450            .remove(&TypeId::of::<T>())
20451            .map(|(_, highlights)| highlights)
20452            .unwrap_or_default();
20453        let ix = highlights.binary_search_by(|highlight| {
20454            Ordering::Equal
20455                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20456                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20457        });
20458        if let Err(ix) = ix {
20459            highlights.insert(ix, range);
20460        }
20461        self.gutter_highlights
20462            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20463    }
20464
20465    pub fn remove_gutter_highlights<T: 'static>(
20466        &mut self,
20467        ranges_to_remove: Vec<Range<Anchor>>,
20468        cx: &mut Context<Self>,
20469    ) {
20470        let snapshot = self.buffer().read(cx).snapshot(cx);
20471        let Some((color_fetcher, mut gutter_highlights)) =
20472            self.gutter_highlights.remove(&TypeId::of::<T>())
20473        else {
20474            return;
20475        };
20476        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20477        gutter_highlights.retain(|highlight| {
20478            while let Some(range_to_remove) = ranges_to_remove.peek() {
20479                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20480                    Ordering::Less | Ordering::Equal => {
20481                        ranges_to_remove.next();
20482                    }
20483                    Ordering::Greater => {
20484                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20485                            Ordering::Less | Ordering::Equal => {
20486                                return false;
20487                            }
20488                            Ordering::Greater => break,
20489                        }
20490                    }
20491                }
20492            }
20493
20494            true
20495        });
20496        self.gutter_highlights
20497            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20498    }
20499
20500    #[cfg(feature = "test-support")]
20501    pub fn all_text_highlights(
20502        &self,
20503        window: &mut Window,
20504        cx: &mut Context<Self>,
20505    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20506        let snapshot = self.snapshot(window, cx);
20507        self.display_map.update(cx, |display_map, _| {
20508            display_map
20509                .all_text_highlights()
20510                .map(|highlight| {
20511                    let (style, ranges) = highlight.as_ref();
20512                    (
20513                        *style,
20514                        ranges
20515                            .iter()
20516                            .map(|range| range.clone().to_display_points(&snapshot))
20517                            .collect(),
20518                    )
20519                })
20520                .collect()
20521        })
20522    }
20523
20524    #[cfg(feature = "test-support")]
20525    pub fn all_text_background_highlights(
20526        &self,
20527        window: &mut Window,
20528        cx: &mut Context<Self>,
20529    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20530        let snapshot = self.snapshot(window, cx);
20531        let buffer = &snapshot.buffer_snapshot();
20532        let start = buffer.anchor_before(0);
20533        let end = buffer.anchor_after(buffer.len());
20534        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20535    }
20536
20537    #[cfg(any(test, feature = "test-support"))]
20538    pub fn sorted_background_highlights_in_range(
20539        &self,
20540        search_range: Range<Anchor>,
20541        display_snapshot: &DisplaySnapshot,
20542        theme: &Theme,
20543    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20544        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20545        res.sort_by(|a, b| {
20546            a.0.start
20547                .cmp(&b.0.start)
20548                .then_with(|| a.0.end.cmp(&b.0.end))
20549                .then_with(|| a.1.cmp(&b.1))
20550        });
20551        res
20552    }
20553
20554    #[cfg(feature = "test-support")]
20555    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20556        let snapshot = self.buffer().read(cx).snapshot(cx);
20557
20558        let highlights = self
20559            .background_highlights
20560            .get(&HighlightKey::Type(TypeId::of::<
20561                items::BufferSearchHighlights,
20562            >()));
20563
20564        if let Some((_color, ranges)) = highlights {
20565            ranges
20566                .iter()
20567                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20568                .collect_vec()
20569        } else {
20570            vec![]
20571        }
20572    }
20573
20574    fn document_highlights_for_position<'a>(
20575        &'a self,
20576        position: Anchor,
20577        buffer: &'a MultiBufferSnapshot,
20578    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20579        let read_highlights = self
20580            .background_highlights
20581            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20582            .map(|h| &h.1);
20583        let write_highlights = self
20584            .background_highlights
20585            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20586            .map(|h| &h.1);
20587        let left_position = position.bias_left(buffer);
20588        let right_position = position.bias_right(buffer);
20589        read_highlights
20590            .into_iter()
20591            .chain(write_highlights)
20592            .flat_map(move |ranges| {
20593                let start_ix = match ranges.binary_search_by(|probe| {
20594                    let cmp = probe.end.cmp(&left_position, buffer);
20595                    if cmp.is_ge() {
20596                        Ordering::Greater
20597                    } else {
20598                        Ordering::Less
20599                    }
20600                }) {
20601                    Ok(i) | Err(i) => i,
20602                };
20603
20604                ranges[start_ix..]
20605                    .iter()
20606                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20607            })
20608    }
20609
20610    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20611        self.background_highlights
20612            .get(&HighlightKey::Type(TypeId::of::<T>()))
20613            .is_some_and(|(_, highlights)| !highlights.is_empty())
20614    }
20615
20616    /// Returns all background highlights for a given range.
20617    ///
20618    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20619    pub fn background_highlights_in_range(
20620        &self,
20621        search_range: Range<Anchor>,
20622        display_snapshot: &DisplaySnapshot,
20623        theme: &Theme,
20624    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20625        let mut results = Vec::new();
20626        for (color_fetcher, ranges) in self.background_highlights.values() {
20627            let color = color_fetcher(theme);
20628            let start_ix = match ranges.binary_search_by(|probe| {
20629                let cmp = probe
20630                    .end
20631                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20632                if cmp.is_gt() {
20633                    Ordering::Greater
20634                } else {
20635                    Ordering::Less
20636                }
20637            }) {
20638                Ok(i) | Err(i) => i,
20639            };
20640            for range in &ranges[start_ix..] {
20641                if range
20642                    .start
20643                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20644                    .is_ge()
20645                {
20646                    break;
20647                }
20648
20649                let start = range.start.to_display_point(display_snapshot);
20650                let end = range.end.to_display_point(display_snapshot);
20651                results.push((start..end, color))
20652            }
20653        }
20654        results
20655    }
20656
20657    pub fn gutter_highlights_in_range(
20658        &self,
20659        search_range: Range<Anchor>,
20660        display_snapshot: &DisplaySnapshot,
20661        cx: &App,
20662    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20663        let mut results = Vec::new();
20664        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20665            let color = color_fetcher(cx);
20666            let start_ix = match ranges.binary_search_by(|probe| {
20667                let cmp = probe
20668                    .end
20669                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20670                if cmp.is_gt() {
20671                    Ordering::Greater
20672                } else {
20673                    Ordering::Less
20674                }
20675            }) {
20676                Ok(i) | Err(i) => i,
20677            };
20678            for range in &ranges[start_ix..] {
20679                if range
20680                    .start
20681                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20682                    .is_ge()
20683                {
20684                    break;
20685                }
20686
20687                let start = range.start.to_display_point(display_snapshot);
20688                let end = range.end.to_display_point(display_snapshot);
20689                results.push((start..end, color))
20690            }
20691        }
20692        results
20693    }
20694
20695    /// Get the text ranges corresponding to the redaction query
20696    pub fn redacted_ranges(
20697        &self,
20698        search_range: Range<Anchor>,
20699        display_snapshot: &DisplaySnapshot,
20700        cx: &App,
20701    ) -> Vec<Range<DisplayPoint>> {
20702        display_snapshot
20703            .buffer_snapshot()
20704            .redacted_ranges(search_range, |file| {
20705                if let Some(file) = file {
20706                    file.is_private()
20707                        && EditorSettings::get(
20708                            Some(SettingsLocation {
20709                                worktree_id: file.worktree_id(cx),
20710                                path: file.path().as_ref(),
20711                            }),
20712                            cx,
20713                        )
20714                        .redact_private_values
20715                } else {
20716                    false
20717                }
20718            })
20719            .map(|range| {
20720                range.start.to_display_point(display_snapshot)
20721                    ..range.end.to_display_point(display_snapshot)
20722            })
20723            .collect()
20724    }
20725
20726    pub fn highlight_text_key<T: 'static>(
20727        &mut self,
20728        key: usize,
20729        ranges: Vec<Range<Anchor>>,
20730        style: HighlightStyle,
20731        cx: &mut Context<Self>,
20732    ) {
20733        self.display_map.update(cx, |map, _| {
20734            map.highlight_text(
20735                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20736                ranges,
20737                style,
20738            );
20739        });
20740        cx.notify();
20741    }
20742
20743    pub fn highlight_text<T: 'static>(
20744        &mut self,
20745        ranges: Vec<Range<Anchor>>,
20746        style: HighlightStyle,
20747        cx: &mut Context<Self>,
20748    ) {
20749        self.display_map.update(cx, |map, _| {
20750            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20751        });
20752        cx.notify();
20753    }
20754
20755    pub fn text_highlights<'a, T: 'static>(
20756        &'a self,
20757        cx: &'a App,
20758    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20759        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20760    }
20761
20762    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20763        let cleared = self
20764            .display_map
20765            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20766        if cleared {
20767            cx.notify();
20768        }
20769    }
20770
20771    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20772        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20773            && self.focus_handle.is_focused(window)
20774    }
20775
20776    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20777        self.show_cursor_when_unfocused = is_enabled;
20778        cx.notify();
20779    }
20780
20781    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20782        cx.notify();
20783    }
20784
20785    fn on_debug_session_event(
20786        &mut self,
20787        _session: Entity<Session>,
20788        event: &SessionEvent,
20789        cx: &mut Context<Self>,
20790    ) {
20791        if let SessionEvent::InvalidateInlineValue = event {
20792            self.refresh_inline_values(cx);
20793        }
20794    }
20795
20796    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20797        let Some(project) = self.project.clone() else {
20798            return;
20799        };
20800
20801        if !self.inline_value_cache.enabled {
20802            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20803            self.splice_inlays(&inlays, Vec::new(), cx);
20804            return;
20805        }
20806
20807        let current_execution_position = self
20808            .highlighted_rows
20809            .get(&TypeId::of::<ActiveDebugLine>())
20810            .and_then(|lines| lines.last().map(|line| line.range.end));
20811
20812        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20813            let inline_values = editor
20814                .update(cx, |editor, cx| {
20815                    let Some(current_execution_position) = current_execution_position else {
20816                        return Some(Task::ready(Ok(Vec::new())));
20817                    };
20818
20819                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20820                        let snapshot = buffer.snapshot(cx);
20821
20822                        let excerpt = snapshot.excerpt_containing(
20823                            current_execution_position..current_execution_position,
20824                        )?;
20825
20826                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20827                    })?;
20828
20829                    let range =
20830                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20831
20832                    project.inline_values(buffer, range, cx)
20833                })
20834                .ok()
20835                .flatten()?
20836                .await
20837                .context("refreshing debugger inlays")
20838                .log_err()?;
20839
20840            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20841
20842            for (buffer_id, inline_value) in inline_values
20843                .into_iter()
20844                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20845            {
20846                buffer_inline_values
20847                    .entry(buffer_id)
20848                    .or_default()
20849                    .push(inline_value);
20850            }
20851
20852            editor
20853                .update(cx, |editor, cx| {
20854                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20855                    let mut new_inlays = Vec::default();
20856
20857                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20858                        let buffer_id = buffer_snapshot.remote_id();
20859                        buffer_inline_values
20860                            .get(&buffer_id)
20861                            .into_iter()
20862                            .flatten()
20863                            .for_each(|hint| {
20864                                let inlay = Inlay::debugger(
20865                                    post_inc(&mut editor.next_inlay_id),
20866                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20867                                    hint.text(),
20868                                );
20869                                if !inlay.text().chars().contains(&'\n') {
20870                                    new_inlays.push(inlay);
20871                                }
20872                            });
20873                    }
20874
20875                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20876                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20877
20878                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20879                })
20880                .ok()?;
20881            Some(())
20882        });
20883    }
20884
20885    fn on_buffer_event(
20886        &mut self,
20887        multibuffer: &Entity<MultiBuffer>,
20888        event: &multi_buffer::Event,
20889        window: &mut Window,
20890        cx: &mut Context<Self>,
20891    ) {
20892        match event {
20893            multi_buffer::Event::Edited { edited_buffer } => {
20894                self.scrollbar_marker_state.dirty = true;
20895                self.active_indent_guides_state.dirty = true;
20896                self.refresh_active_diagnostics(cx);
20897                self.refresh_code_actions(window, cx);
20898                self.refresh_selected_text_highlights(true, window, cx);
20899                self.refresh_single_line_folds(window, cx);
20900                self.refresh_matching_bracket_highlights(window, cx);
20901                if self.has_active_edit_prediction() {
20902                    self.update_visible_edit_prediction(window, cx);
20903                }
20904
20905                if let Some(buffer) = edited_buffer {
20906                    if buffer.read(cx).file().is_none() {
20907                        cx.emit(EditorEvent::TitleChanged);
20908                    }
20909
20910                    if self.project.is_some() {
20911                        let buffer_id = buffer.read(cx).remote_id();
20912                        self.register_buffer(buffer_id, cx);
20913                        self.update_lsp_data(Some(buffer_id), window, cx);
20914                        self.refresh_inlay_hints(
20915                            InlayHintRefreshReason::BufferEdited(buffer_id),
20916                            cx,
20917                        );
20918                    }
20919                }
20920
20921                cx.emit(EditorEvent::BufferEdited);
20922                cx.emit(SearchEvent::MatchesInvalidated);
20923
20924                let Some(project) = &self.project else { return };
20925                let (telemetry, is_via_ssh) = {
20926                    let project = project.read(cx);
20927                    let telemetry = project.client().telemetry().clone();
20928                    let is_via_ssh = project.is_via_remote_server();
20929                    (telemetry, is_via_ssh)
20930                };
20931                telemetry.log_edit_event("editor", is_via_ssh);
20932            }
20933            multi_buffer::Event::ExcerptsAdded {
20934                buffer,
20935                predecessor,
20936                excerpts,
20937            } => {
20938                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20939                let buffer_id = buffer.read(cx).remote_id();
20940                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20941                    && let Some(project) = &self.project
20942                {
20943                    update_uncommitted_diff_for_buffer(
20944                        cx.entity(),
20945                        project,
20946                        [buffer.clone()],
20947                        self.buffer.clone(),
20948                        cx,
20949                    )
20950                    .detach();
20951                }
20952                self.update_lsp_data(Some(buffer_id), window, cx);
20953                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20954                cx.emit(EditorEvent::ExcerptsAdded {
20955                    buffer: buffer.clone(),
20956                    predecessor: *predecessor,
20957                    excerpts: excerpts.clone(),
20958                });
20959            }
20960            multi_buffer::Event::ExcerptsRemoved {
20961                ids,
20962                removed_buffer_ids,
20963            } => {
20964                if let Some(inlay_hints) = &mut self.inlay_hints {
20965                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
20966                }
20967                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20968                for buffer_id in removed_buffer_ids {
20969                    self.registered_buffers.remove(buffer_id);
20970                }
20971                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20972                cx.emit(EditorEvent::ExcerptsRemoved {
20973                    ids: ids.clone(),
20974                    removed_buffer_ids: removed_buffer_ids.clone(),
20975                });
20976            }
20977            multi_buffer::Event::ExcerptsEdited {
20978                excerpt_ids,
20979                buffer_ids,
20980            } => {
20981                self.display_map.update(cx, |map, cx| {
20982                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20983                });
20984                cx.emit(EditorEvent::ExcerptsEdited {
20985                    ids: excerpt_ids.clone(),
20986                });
20987            }
20988            multi_buffer::Event::ExcerptsExpanded { ids } => {
20989                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20990                self.refresh_document_highlights(cx);
20991                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20992            }
20993            multi_buffer::Event::Reparsed(buffer_id) => {
20994                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20995                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20996
20997                cx.emit(EditorEvent::Reparsed(*buffer_id));
20998            }
20999            multi_buffer::Event::DiffHunksToggled => {
21000                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21001            }
21002            multi_buffer::Event::LanguageChanged(buffer_id) => {
21003                self.registered_buffers.remove(&buffer_id);
21004                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21005                cx.emit(EditorEvent::Reparsed(*buffer_id));
21006                cx.notify();
21007            }
21008            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21009            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21010            multi_buffer::Event::FileHandleChanged
21011            | multi_buffer::Event::Reloaded
21012            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21013            multi_buffer::Event::DiagnosticsUpdated => {
21014                self.update_diagnostics_state(window, cx);
21015            }
21016            _ => {}
21017        };
21018    }
21019
21020    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21021        if !self.diagnostics_enabled() {
21022            return;
21023        }
21024        self.refresh_active_diagnostics(cx);
21025        self.refresh_inline_diagnostics(true, window, cx);
21026        self.scrollbar_marker_state.dirty = true;
21027        cx.notify();
21028    }
21029
21030    pub fn start_temporary_diff_override(&mut self) {
21031        self.load_diff_task.take();
21032        self.temporary_diff_override = true;
21033    }
21034
21035    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21036        self.temporary_diff_override = false;
21037        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21038        self.buffer.update(cx, |buffer, cx| {
21039            buffer.set_all_diff_hunks_collapsed(cx);
21040        });
21041
21042        if let Some(project) = self.project.clone() {
21043            self.load_diff_task = Some(
21044                update_uncommitted_diff_for_buffer(
21045                    cx.entity(),
21046                    &project,
21047                    self.buffer.read(cx).all_buffers(),
21048                    self.buffer.clone(),
21049                    cx,
21050                )
21051                .shared(),
21052            );
21053        }
21054    }
21055
21056    fn on_display_map_changed(
21057        &mut self,
21058        _: Entity<DisplayMap>,
21059        _: &mut Window,
21060        cx: &mut Context<Self>,
21061    ) {
21062        cx.notify();
21063    }
21064
21065    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21066        if self.diagnostics_enabled() {
21067            let new_severity = EditorSettings::get_global(cx)
21068                .diagnostics_max_severity
21069                .unwrap_or(DiagnosticSeverity::Hint);
21070            self.set_max_diagnostics_severity(new_severity, cx);
21071        }
21072        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21073        self.update_edit_prediction_settings(cx);
21074        self.refresh_edit_prediction(true, false, window, cx);
21075        self.refresh_inline_values(cx);
21076        self.refresh_inlay_hints(
21077            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21078                self.selections.newest_anchor().head(),
21079                &self.buffer.read(cx).snapshot(cx),
21080                cx,
21081            )),
21082            cx,
21083        );
21084
21085        let old_cursor_shape = self.cursor_shape;
21086        let old_show_breadcrumbs = self.show_breadcrumbs;
21087
21088        {
21089            let editor_settings = EditorSettings::get_global(cx);
21090            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21091            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21092            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21093            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21094        }
21095
21096        if old_cursor_shape != self.cursor_shape {
21097            cx.emit(EditorEvent::CursorShapeChanged);
21098        }
21099
21100        if old_show_breadcrumbs != self.show_breadcrumbs {
21101            cx.emit(EditorEvent::BreadcrumbsChanged);
21102        }
21103
21104        let project_settings = ProjectSettings::get_global(cx);
21105        self.serialize_dirty_buffers =
21106            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21107
21108        if self.mode.is_full() {
21109            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21110            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21111            if self.show_inline_diagnostics != show_inline_diagnostics {
21112                self.show_inline_diagnostics = show_inline_diagnostics;
21113                self.refresh_inline_diagnostics(false, window, cx);
21114            }
21115
21116            if self.git_blame_inline_enabled != inline_blame_enabled {
21117                self.toggle_git_blame_inline_internal(false, window, cx);
21118            }
21119
21120            let minimap_settings = EditorSettings::get_global(cx).minimap;
21121            if self.minimap_visibility != MinimapVisibility::Disabled {
21122                if self.minimap_visibility.settings_visibility()
21123                    != minimap_settings.minimap_enabled()
21124                {
21125                    self.set_minimap_visibility(
21126                        MinimapVisibility::for_mode(self.mode(), cx),
21127                        window,
21128                        cx,
21129                    );
21130                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21131                    minimap_entity.update(cx, |minimap_editor, cx| {
21132                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21133                    })
21134                }
21135            }
21136        }
21137
21138        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21139            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21140        }) {
21141            if !inlay_splice.is_empty() {
21142                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21143            }
21144            self.refresh_colors_for_visible_range(None, window, cx);
21145        }
21146
21147        cx.notify();
21148    }
21149
21150    pub fn set_searchable(&mut self, searchable: bool) {
21151        self.searchable = searchable;
21152    }
21153
21154    pub fn searchable(&self) -> bool {
21155        self.searchable
21156    }
21157
21158    pub fn open_excerpts_in_split(
21159        &mut self,
21160        _: &OpenExcerptsSplit,
21161        window: &mut Window,
21162        cx: &mut Context<Self>,
21163    ) {
21164        self.open_excerpts_common(None, true, window, cx)
21165    }
21166
21167    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21168        self.open_excerpts_common(None, false, window, cx)
21169    }
21170
21171    fn open_excerpts_common(
21172        &mut self,
21173        jump_data: Option<JumpData>,
21174        split: bool,
21175        window: &mut Window,
21176        cx: &mut Context<Self>,
21177    ) {
21178        let Some(workspace) = self.workspace() else {
21179            cx.propagate();
21180            return;
21181        };
21182
21183        if self.buffer.read(cx).is_singleton() {
21184            cx.propagate();
21185            return;
21186        }
21187
21188        let mut new_selections_by_buffer = HashMap::default();
21189        match &jump_data {
21190            Some(JumpData::MultiBufferPoint {
21191                excerpt_id,
21192                position,
21193                anchor,
21194                line_offset_from_top,
21195            }) => {
21196                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21197                if let Some(buffer) = multi_buffer_snapshot
21198                    .buffer_id_for_excerpt(*excerpt_id)
21199                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21200                {
21201                    let buffer_snapshot = buffer.read(cx).snapshot();
21202                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21203                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21204                    } else {
21205                        buffer_snapshot.clip_point(*position, Bias::Left)
21206                    };
21207                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21208                    new_selections_by_buffer.insert(
21209                        buffer,
21210                        (
21211                            vec![jump_to_offset..jump_to_offset],
21212                            Some(*line_offset_from_top),
21213                        ),
21214                    );
21215                }
21216            }
21217            Some(JumpData::MultiBufferRow {
21218                row,
21219                line_offset_from_top,
21220            }) => {
21221                let point = MultiBufferPoint::new(row.0, 0);
21222                if let Some((buffer, buffer_point, _)) =
21223                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21224                {
21225                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21226                    new_selections_by_buffer
21227                        .entry(buffer)
21228                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21229                        .0
21230                        .push(buffer_offset..buffer_offset)
21231                }
21232            }
21233            None => {
21234                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21235                let multi_buffer = self.buffer.read(cx);
21236                for selection in selections {
21237                    for (snapshot, range, _, anchor) in multi_buffer
21238                        .snapshot(cx)
21239                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21240                    {
21241                        if let Some(anchor) = anchor {
21242                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21243                            else {
21244                                continue;
21245                            };
21246                            let offset = text::ToOffset::to_offset(
21247                                &anchor.text_anchor,
21248                                &buffer_handle.read(cx).snapshot(),
21249                            );
21250                            let range = offset..offset;
21251                            new_selections_by_buffer
21252                                .entry(buffer_handle)
21253                                .or_insert((Vec::new(), None))
21254                                .0
21255                                .push(range)
21256                        } else {
21257                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21258                            else {
21259                                continue;
21260                            };
21261                            new_selections_by_buffer
21262                                .entry(buffer_handle)
21263                                .or_insert((Vec::new(), None))
21264                                .0
21265                                .push(range)
21266                        }
21267                    }
21268                }
21269            }
21270        }
21271
21272        new_selections_by_buffer
21273            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21274
21275        if new_selections_by_buffer.is_empty() {
21276            return;
21277        }
21278
21279        // We defer the pane interaction because we ourselves are a workspace item
21280        // and activating a new item causes the pane to call a method on us reentrantly,
21281        // which panics if we're on the stack.
21282        window.defer(cx, move |window, cx| {
21283            workspace.update(cx, |workspace, cx| {
21284                let pane = if split {
21285                    workspace.adjacent_pane(window, cx)
21286                } else {
21287                    workspace.active_pane().clone()
21288                };
21289
21290                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21291                    let editor = buffer
21292                        .read(cx)
21293                        .file()
21294                        .is_none()
21295                        .then(|| {
21296                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21297                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21298                            // Instead, we try to activate the existing editor in the pane first.
21299                            let (editor, pane_item_index) =
21300                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21301                                    let editor = item.downcast::<Editor>()?;
21302                                    let singleton_buffer =
21303                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21304                                    if singleton_buffer == buffer {
21305                                        Some((editor, i))
21306                                    } else {
21307                                        None
21308                                    }
21309                                })?;
21310                            pane.update(cx, |pane, cx| {
21311                                pane.activate_item(pane_item_index, true, true, window, cx)
21312                            });
21313                            Some(editor)
21314                        })
21315                        .flatten()
21316                        .unwrap_or_else(|| {
21317                            workspace.open_project_item::<Self>(
21318                                pane.clone(),
21319                                buffer,
21320                                true,
21321                                true,
21322                                window,
21323                                cx,
21324                            )
21325                        });
21326
21327                    editor.update(cx, |editor, cx| {
21328                        let autoscroll = match scroll_offset {
21329                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21330                            None => Autoscroll::newest(),
21331                        };
21332                        let nav_history = editor.nav_history.take();
21333                        editor.change_selections(
21334                            SelectionEffects::scroll(autoscroll),
21335                            window,
21336                            cx,
21337                            |s| {
21338                                s.select_ranges(ranges);
21339                            },
21340                        );
21341                        editor.nav_history = nav_history;
21342                    });
21343                }
21344            })
21345        });
21346    }
21347
21348    // For now, don't allow opening excerpts in buffers that aren't backed by
21349    // regular project files.
21350    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21351        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21352    }
21353
21354    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21355        let snapshot = self.buffer.read(cx).read(cx);
21356        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21357        Some(
21358            ranges
21359                .iter()
21360                .map(move |range| {
21361                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21362                })
21363                .collect(),
21364        )
21365    }
21366
21367    fn selection_replacement_ranges(
21368        &self,
21369        range: Range<OffsetUtf16>,
21370        cx: &mut App,
21371    ) -> Vec<Range<OffsetUtf16>> {
21372        let selections = self
21373            .selections
21374            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21375        let newest_selection = selections
21376            .iter()
21377            .max_by_key(|selection| selection.id)
21378            .unwrap();
21379        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21380        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21381        let snapshot = self.buffer.read(cx).read(cx);
21382        selections
21383            .into_iter()
21384            .map(|mut selection| {
21385                selection.start.0 =
21386                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21387                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21388                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21389                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21390            })
21391            .collect()
21392    }
21393
21394    fn report_editor_event(
21395        &self,
21396        reported_event: ReportEditorEvent,
21397        file_extension: Option<String>,
21398        cx: &App,
21399    ) {
21400        if cfg!(any(test, feature = "test-support")) {
21401            return;
21402        }
21403
21404        let Some(project) = &self.project else { return };
21405
21406        // If None, we are in a file without an extension
21407        let file = self
21408            .buffer
21409            .read(cx)
21410            .as_singleton()
21411            .and_then(|b| b.read(cx).file());
21412        let file_extension = file_extension.or(file
21413            .as_ref()
21414            .and_then(|file| Path::new(file.file_name(cx)).extension())
21415            .and_then(|e| e.to_str())
21416            .map(|a| a.to_string()));
21417
21418        let vim_mode = vim_enabled(cx);
21419
21420        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21421        let copilot_enabled = edit_predictions_provider
21422            == language::language_settings::EditPredictionProvider::Copilot;
21423        let copilot_enabled_for_language = self
21424            .buffer
21425            .read(cx)
21426            .language_settings(cx)
21427            .show_edit_predictions;
21428
21429        let project = project.read(cx);
21430        let event_type = reported_event.event_type();
21431
21432        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21433            telemetry::event!(
21434                event_type,
21435                type = if auto_saved {"autosave"} else {"manual"},
21436                file_extension,
21437                vim_mode,
21438                copilot_enabled,
21439                copilot_enabled_for_language,
21440                edit_predictions_provider,
21441                is_via_ssh = project.is_via_remote_server(),
21442            );
21443        } else {
21444            telemetry::event!(
21445                event_type,
21446                file_extension,
21447                vim_mode,
21448                copilot_enabled,
21449                copilot_enabled_for_language,
21450                edit_predictions_provider,
21451                is_via_ssh = project.is_via_remote_server(),
21452            );
21453        };
21454    }
21455
21456    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21457    /// with each line being an array of {text, highlight} objects.
21458    fn copy_highlight_json(
21459        &mut self,
21460        _: &CopyHighlightJson,
21461        window: &mut Window,
21462        cx: &mut Context<Self>,
21463    ) {
21464        #[derive(Serialize)]
21465        struct Chunk<'a> {
21466            text: String,
21467            highlight: Option<&'a str>,
21468        }
21469
21470        let snapshot = self.buffer.read(cx).snapshot(cx);
21471        let range = self
21472            .selected_text_range(false, window, cx)
21473            .and_then(|selection| {
21474                if selection.range.is_empty() {
21475                    None
21476                } else {
21477                    Some(
21478                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21479                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21480                    )
21481                }
21482            })
21483            .unwrap_or_else(|| 0..snapshot.len());
21484
21485        let chunks = snapshot.chunks(range, true);
21486        let mut lines = Vec::new();
21487        let mut line: VecDeque<Chunk> = VecDeque::new();
21488
21489        let Some(style) = self.style.as_ref() else {
21490            return;
21491        };
21492
21493        for chunk in chunks {
21494            let highlight = chunk
21495                .syntax_highlight_id
21496                .and_then(|id| id.name(&style.syntax));
21497            let mut chunk_lines = chunk.text.split('\n').peekable();
21498            while let Some(text) = chunk_lines.next() {
21499                let mut merged_with_last_token = false;
21500                if let Some(last_token) = line.back_mut()
21501                    && last_token.highlight == highlight
21502                {
21503                    last_token.text.push_str(text);
21504                    merged_with_last_token = true;
21505                }
21506
21507                if !merged_with_last_token {
21508                    line.push_back(Chunk {
21509                        text: text.into(),
21510                        highlight,
21511                    });
21512                }
21513
21514                if chunk_lines.peek().is_some() {
21515                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21516                        line.pop_front();
21517                    }
21518                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21519                        line.pop_back();
21520                    }
21521
21522                    lines.push(mem::take(&mut line));
21523                }
21524            }
21525        }
21526
21527        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21528            return;
21529        };
21530        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21531    }
21532
21533    pub fn open_context_menu(
21534        &mut self,
21535        _: &OpenContextMenu,
21536        window: &mut Window,
21537        cx: &mut Context<Self>,
21538    ) {
21539        self.request_autoscroll(Autoscroll::newest(), cx);
21540        let position = self
21541            .selections
21542            .newest_display(&self.display_snapshot(cx))
21543            .start;
21544        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21545    }
21546
21547    pub fn replay_insert_event(
21548        &mut self,
21549        text: &str,
21550        relative_utf16_range: Option<Range<isize>>,
21551        window: &mut Window,
21552        cx: &mut Context<Self>,
21553    ) {
21554        if !self.input_enabled {
21555            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21556            return;
21557        }
21558        if let Some(relative_utf16_range) = relative_utf16_range {
21559            let selections = self
21560                .selections
21561                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21562            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21563                let new_ranges = selections.into_iter().map(|range| {
21564                    let start = OffsetUtf16(
21565                        range
21566                            .head()
21567                            .0
21568                            .saturating_add_signed(relative_utf16_range.start),
21569                    );
21570                    let end = OffsetUtf16(
21571                        range
21572                            .head()
21573                            .0
21574                            .saturating_add_signed(relative_utf16_range.end),
21575                    );
21576                    start..end
21577                });
21578                s.select_ranges(new_ranges);
21579            });
21580        }
21581
21582        self.handle_input(text, window, cx);
21583    }
21584
21585    pub fn is_focused(&self, window: &Window) -> bool {
21586        self.focus_handle.is_focused(window)
21587    }
21588
21589    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21590        cx.emit(EditorEvent::Focused);
21591
21592        if let Some(descendant) = self
21593            .last_focused_descendant
21594            .take()
21595            .and_then(|descendant| descendant.upgrade())
21596        {
21597            window.focus(&descendant);
21598        } else {
21599            if let Some(blame) = self.blame.as_ref() {
21600                blame.update(cx, GitBlame::focus)
21601            }
21602
21603            self.blink_manager.update(cx, BlinkManager::enable);
21604            self.show_cursor_names(window, cx);
21605            self.buffer.update(cx, |buffer, cx| {
21606                buffer.finalize_last_transaction(cx);
21607                if self.leader_id.is_none() {
21608                    buffer.set_active_selections(
21609                        &self.selections.disjoint_anchors_arc(),
21610                        self.selections.line_mode(),
21611                        self.cursor_shape,
21612                        cx,
21613                    );
21614                }
21615            });
21616        }
21617    }
21618
21619    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21620        cx.emit(EditorEvent::FocusedIn)
21621    }
21622
21623    fn handle_focus_out(
21624        &mut self,
21625        event: FocusOutEvent,
21626        _window: &mut Window,
21627        cx: &mut Context<Self>,
21628    ) {
21629        if event.blurred != self.focus_handle {
21630            self.last_focused_descendant = Some(event.blurred);
21631        }
21632        self.selection_drag_state = SelectionDragState::None;
21633        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21634    }
21635
21636    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21637        self.blink_manager.update(cx, BlinkManager::disable);
21638        self.buffer
21639            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21640
21641        if let Some(blame) = self.blame.as_ref() {
21642            blame.update(cx, GitBlame::blur)
21643        }
21644        if !self.hover_state.focused(window, cx) {
21645            hide_hover(self, cx);
21646        }
21647        if !self
21648            .context_menu
21649            .borrow()
21650            .as_ref()
21651            .is_some_and(|context_menu| context_menu.focused(window, cx))
21652        {
21653            self.hide_context_menu(window, cx);
21654        }
21655        self.take_active_edit_prediction(cx);
21656        cx.emit(EditorEvent::Blurred);
21657        cx.notify();
21658    }
21659
21660    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21661        let mut pending: String = window
21662            .pending_input_keystrokes()
21663            .into_iter()
21664            .flatten()
21665            .filter_map(|keystroke| {
21666                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21667                    keystroke.key_char.clone()
21668                } else {
21669                    None
21670                }
21671            })
21672            .collect();
21673
21674        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21675            pending = "".to_string();
21676        }
21677
21678        let existing_pending = self
21679            .text_highlights::<PendingInput>(cx)
21680            .map(|(_, ranges)| ranges.to_vec());
21681        if existing_pending.is_none() && pending.is_empty() {
21682            return;
21683        }
21684        let transaction =
21685            self.transact(window, cx, |this, window, cx| {
21686                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21687                let edits = selections
21688                    .iter()
21689                    .map(|selection| (selection.end..selection.end, pending.clone()));
21690                this.edit(edits, cx);
21691                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21692                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21693                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21694                    }));
21695                });
21696                if let Some(existing_ranges) = existing_pending {
21697                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21698                    this.edit(edits, cx);
21699                }
21700            });
21701
21702        let snapshot = self.snapshot(window, cx);
21703        let ranges = self
21704            .selections
21705            .all::<usize>(&snapshot.display_snapshot)
21706            .into_iter()
21707            .map(|selection| {
21708                snapshot.buffer_snapshot().anchor_after(selection.end)
21709                    ..snapshot
21710                        .buffer_snapshot()
21711                        .anchor_before(selection.end + pending.len())
21712            })
21713            .collect();
21714
21715        if pending.is_empty() {
21716            self.clear_highlights::<PendingInput>(cx);
21717        } else {
21718            self.highlight_text::<PendingInput>(
21719                ranges,
21720                HighlightStyle {
21721                    underline: Some(UnderlineStyle {
21722                        thickness: px(1.),
21723                        color: None,
21724                        wavy: false,
21725                    }),
21726                    ..Default::default()
21727                },
21728                cx,
21729            );
21730        }
21731
21732        self.ime_transaction = self.ime_transaction.or(transaction);
21733        if let Some(transaction) = self.ime_transaction {
21734            self.buffer.update(cx, |buffer, cx| {
21735                buffer.group_until_transaction(transaction, cx);
21736            });
21737        }
21738
21739        if self.text_highlights::<PendingInput>(cx).is_none() {
21740            self.ime_transaction.take();
21741        }
21742    }
21743
21744    pub fn register_action_renderer(
21745        &mut self,
21746        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21747    ) -> Subscription {
21748        let id = self.next_editor_action_id.post_inc();
21749        self.editor_actions
21750            .borrow_mut()
21751            .insert(id, Box::new(listener));
21752
21753        let editor_actions = self.editor_actions.clone();
21754        Subscription::new(move || {
21755            editor_actions.borrow_mut().remove(&id);
21756        })
21757    }
21758
21759    pub fn register_action<A: Action>(
21760        &mut self,
21761        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21762    ) -> Subscription {
21763        let id = self.next_editor_action_id.post_inc();
21764        let listener = Arc::new(listener);
21765        self.editor_actions.borrow_mut().insert(
21766            id,
21767            Box::new(move |_, window, _| {
21768                let listener = listener.clone();
21769                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21770                    let action = action.downcast_ref().unwrap();
21771                    if phase == DispatchPhase::Bubble {
21772                        listener(action, window, cx)
21773                    }
21774                })
21775            }),
21776        );
21777
21778        let editor_actions = self.editor_actions.clone();
21779        Subscription::new(move || {
21780            editor_actions.borrow_mut().remove(&id);
21781        })
21782    }
21783
21784    pub fn file_header_size(&self) -> u32 {
21785        FILE_HEADER_HEIGHT
21786    }
21787
21788    pub fn restore(
21789        &mut self,
21790        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21791        window: &mut Window,
21792        cx: &mut Context<Self>,
21793    ) {
21794        let workspace = self.workspace();
21795        let project = self.project();
21796        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21797            let mut tasks = Vec::new();
21798            for (buffer_id, changes) in revert_changes {
21799                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21800                    buffer.update(cx, |buffer, cx| {
21801                        buffer.edit(
21802                            changes
21803                                .into_iter()
21804                                .map(|(range, text)| (range, text.to_string())),
21805                            None,
21806                            cx,
21807                        );
21808                    });
21809
21810                    if let Some(project) =
21811                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21812                    {
21813                        project.update(cx, |project, cx| {
21814                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21815                        })
21816                    }
21817                }
21818            }
21819            tasks
21820        });
21821        cx.spawn_in(window, async move |_, cx| {
21822            for (buffer, task) in save_tasks {
21823                let result = task.await;
21824                if result.is_err() {
21825                    let Some(path) = buffer
21826                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21827                        .ok()
21828                    else {
21829                        continue;
21830                    };
21831                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21832                        let Some(task) = cx
21833                            .update_window_entity(workspace, |workspace, window, cx| {
21834                                workspace
21835                                    .open_path_preview(path, None, false, false, false, window, cx)
21836                            })
21837                            .ok()
21838                        else {
21839                            continue;
21840                        };
21841                        task.await.log_err();
21842                    }
21843                }
21844            }
21845        })
21846        .detach();
21847        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21848            selections.refresh()
21849        });
21850    }
21851
21852    pub fn to_pixel_point(
21853        &self,
21854        source: multi_buffer::Anchor,
21855        editor_snapshot: &EditorSnapshot,
21856        window: &mut Window,
21857    ) -> Option<gpui::Point<Pixels>> {
21858        let source_point = source.to_display_point(editor_snapshot);
21859        self.display_to_pixel_point(source_point, editor_snapshot, window)
21860    }
21861
21862    pub fn display_to_pixel_point(
21863        &self,
21864        source: DisplayPoint,
21865        editor_snapshot: &EditorSnapshot,
21866        window: &mut Window,
21867    ) -> Option<gpui::Point<Pixels>> {
21868        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21869        let text_layout_details = self.text_layout_details(window);
21870        let scroll_top = text_layout_details
21871            .scroll_anchor
21872            .scroll_position(editor_snapshot)
21873            .y;
21874
21875        if source.row().as_f64() < scroll_top.floor() {
21876            return None;
21877        }
21878        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21879        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21880        Some(gpui::Point::new(source_x, source_y))
21881    }
21882
21883    pub fn has_visible_completions_menu(&self) -> bool {
21884        !self.edit_prediction_preview_is_active()
21885            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21886                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21887            })
21888    }
21889
21890    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21891        if self.mode.is_minimap() {
21892            return;
21893        }
21894        self.addons
21895            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21896    }
21897
21898    pub fn unregister_addon<T: Addon>(&mut self) {
21899        self.addons.remove(&std::any::TypeId::of::<T>());
21900    }
21901
21902    pub fn addon<T: Addon>(&self) -> Option<&T> {
21903        let type_id = std::any::TypeId::of::<T>();
21904        self.addons
21905            .get(&type_id)
21906            .and_then(|item| item.to_any().downcast_ref::<T>())
21907    }
21908
21909    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21910        let type_id = std::any::TypeId::of::<T>();
21911        self.addons
21912            .get_mut(&type_id)
21913            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21914    }
21915
21916    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21917        let text_layout_details = self.text_layout_details(window);
21918        let style = &text_layout_details.editor_style;
21919        let font_id = window.text_system().resolve_font(&style.text.font());
21920        let font_size = style.text.font_size.to_pixels(window.rem_size());
21921        let line_height = style.text.line_height_in_pixels(window.rem_size());
21922        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21923        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21924
21925        CharacterDimensions {
21926            em_width,
21927            em_advance,
21928            line_height,
21929        }
21930    }
21931
21932    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21933        self.load_diff_task.clone()
21934    }
21935
21936    fn read_metadata_from_db(
21937        &mut self,
21938        item_id: u64,
21939        workspace_id: WorkspaceId,
21940        window: &mut Window,
21941        cx: &mut Context<Editor>,
21942    ) {
21943        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21944            && !self.mode.is_minimap()
21945            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21946        {
21947            let buffer_snapshot = OnceCell::new();
21948
21949            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21950                && !folds.is_empty()
21951            {
21952                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21953                self.fold_ranges(
21954                    folds
21955                        .into_iter()
21956                        .map(|(start, end)| {
21957                            snapshot.clip_offset(start, Bias::Left)
21958                                ..snapshot.clip_offset(end, Bias::Right)
21959                        })
21960                        .collect(),
21961                    false,
21962                    window,
21963                    cx,
21964                );
21965            }
21966
21967            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21968                && !selections.is_empty()
21969            {
21970                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21971                // skip adding the initial selection to selection history
21972                self.selection_history.mode = SelectionHistoryMode::Skipping;
21973                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21974                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21975                        snapshot.clip_offset(start, Bias::Left)
21976                            ..snapshot.clip_offset(end, Bias::Right)
21977                    }));
21978                });
21979                self.selection_history.mode = SelectionHistoryMode::Normal;
21980            };
21981        }
21982
21983        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21984    }
21985
21986    fn update_lsp_data(
21987        &mut self,
21988        for_buffer: Option<BufferId>,
21989        window: &mut Window,
21990        cx: &mut Context<'_, Self>,
21991    ) {
21992        self.pull_diagnostics(for_buffer, window, cx);
21993        self.refresh_colors_for_visible_range(for_buffer, window, cx);
21994    }
21995
21996    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
21997        if self.ignore_lsp_data() {
21998            return;
21999        }
22000        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22001            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22002        }
22003    }
22004
22005    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22006        if !self.registered_buffers.contains_key(&buffer_id)
22007            && let Some(project) = self.project.as_ref()
22008        {
22009            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22010                project.update(cx, |project, cx| {
22011                    self.registered_buffers.insert(
22012                        buffer_id,
22013                        project.register_buffer_with_language_servers(&buffer, cx),
22014                    );
22015                });
22016            } else {
22017                self.registered_buffers.remove(&buffer_id);
22018            }
22019        }
22020    }
22021
22022    fn ignore_lsp_data(&self) -> bool {
22023        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22024        // skip any LSP updates for it.
22025        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22026    }
22027}
22028
22029fn edit_for_markdown_paste<'a>(
22030    buffer: &MultiBufferSnapshot,
22031    range: Range<usize>,
22032    to_insert: &'a str,
22033    url: Option<url::Url>,
22034) -> (Range<usize>, Cow<'a, str>) {
22035    if url.is_none() {
22036        return (range, Cow::Borrowed(to_insert));
22037    };
22038
22039    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22040
22041    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22042        Cow::Borrowed(to_insert)
22043    } else {
22044        Cow::Owned(format!("[{old_text}]({to_insert})"))
22045    };
22046    (range, new_text)
22047}
22048
22049fn vim_enabled(cx: &App) -> bool {
22050    vim_mode_setting::VimModeSetting::try_get(cx)
22051        .map(|vim_mode| vim_mode.0)
22052        .unwrap_or(false)
22053}
22054
22055fn process_completion_for_edit(
22056    completion: &Completion,
22057    intent: CompletionIntent,
22058    buffer: &Entity<Buffer>,
22059    cursor_position: &text::Anchor,
22060    cx: &mut Context<Editor>,
22061) -> CompletionEdit {
22062    let buffer = buffer.read(cx);
22063    let buffer_snapshot = buffer.snapshot();
22064    let (snippet, new_text) = if completion.is_snippet() {
22065        let mut snippet_source = completion.new_text.clone();
22066        // Workaround for typescript language server issues so that methods don't expand within
22067        // strings and functions with type expressions. The previous point is used because the query
22068        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22069        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22070        let previous_point = if previous_point.column > 0 {
22071            cursor_position.to_previous_offset(&buffer_snapshot)
22072        } else {
22073            cursor_position.to_offset(&buffer_snapshot)
22074        };
22075        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22076            && scope.prefers_label_for_snippet_in_completion()
22077            && let Some(label) = completion.label()
22078            && matches!(
22079                completion.kind(),
22080                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22081            )
22082        {
22083            snippet_source = label;
22084        }
22085        match Snippet::parse(&snippet_source).log_err() {
22086            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22087            None => (None, completion.new_text.clone()),
22088        }
22089    } else {
22090        (None, completion.new_text.clone())
22091    };
22092
22093    let mut range_to_replace = {
22094        let replace_range = &completion.replace_range;
22095        if let CompletionSource::Lsp {
22096            insert_range: Some(insert_range),
22097            ..
22098        } = &completion.source
22099        {
22100            debug_assert_eq!(
22101                insert_range.start, replace_range.start,
22102                "insert_range and replace_range should start at the same position"
22103            );
22104            debug_assert!(
22105                insert_range
22106                    .start
22107                    .cmp(cursor_position, &buffer_snapshot)
22108                    .is_le(),
22109                "insert_range should start before or at cursor position"
22110            );
22111            debug_assert!(
22112                replace_range
22113                    .start
22114                    .cmp(cursor_position, &buffer_snapshot)
22115                    .is_le(),
22116                "replace_range should start before or at cursor position"
22117            );
22118
22119            let should_replace = match intent {
22120                CompletionIntent::CompleteWithInsert => false,
22121                CompletionIntent::CompleteWithReplace => true,
22122                CompletionIntent::Complete | CompletionIntent::Compose => {
22123                    let insert_mode =
22124                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22125                            .completions
22126                            .lsp_insert_mode;
22127                    match insert_mode {
22128                        LspInsertMode::Insert => false,
22129                        LspInsertMode::Replace => true,
22130                        LspInsertMode::ReplaceSubsequence => {
22131                            let mut text_to_replace = buffer.chars_for_range(
22132                                buffer.anchor_before(replace_range.start)
22133                                    ..buffer.anchor_after(replace_range.end),
22134                            );
22135                            let mut current_needle = text_to_replace.next();
22136                            for haystack_ch in completion.label.text.chars() {
22137                                if let Some(needle_ch) = current_needle
22138                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22139                                {
22140                                    current_needle = text_to_replace.next();
22141                                }
22142                            }
22143                            current_needle.is_none()
22144                        }
22145                        LspInsertMode::ReplaceSuffix => {
22146                            if replace_range
22147                                .end
22148                                .cmp(cursor_position, &buffer_snapshot)
22149                                .is_gt()
22150                            {
22151                                let range_after_cursor = *cursor_position..replace_range.end;
22152                                let text_after_cursor = buffer
22153                                    .text_for_range(
22154                                        buffer.anchor_before(range_after_cursor.start)
22155                                            ..buffer.anchor_after(range_after_cursor.end),
22156                                    )
22157                                    .collect::<String>()
22158                                    .to_ascii_lowercase();
22159                                completion
22160                                    .label
22161                                    .text
22162                                    .to_ascii_lowercase()
22163                                    .ends_with(&text_after_cursor)
22164                            } else {
22165                                true
22166                            }
22167                        }
22168                    }
22169                }
22170            };
22171
22172            if should_replace {
22173                replace_range.clone()
22174            } else {
22175                insert_range.clone()
22176            }
22177        } else {
22178            replace_range.clone()
22179        }
22180    };
22181
22182    if range_to_replace
22183        .end
22184        .cmp(cursor_position, &buffer_snapshot)
22185        .is_lt()
22186    {
22187        range_to_replace.end = *cursor_position;
22188    }
22189
22190    CompletionEdit {
22191        new_text,
22192        replace_range: range_to_replace.to_offset(buffer),
22193        snippet,
22194    }
22195}
22196
22197struct CompletionEdit {
22198    new_text: String,
22199    replace_range: Range<usize>,
22200    snippet: Option<Snippet>,
22201}
22202
22203fn insert_extra_newline_brackets(
22204    buffer: &MultiBufferSnapshot,
22205    range: Range<usize>,
22206    language: &language::LanguageScope,
22207) -> bool {
22208    let leading_whitespace_len = buffer
22209        .reversed_chars_at(range.start)
22210        .take_while(|c| c.is_whitespace() && *c != '\n')
22211        .map(|c| c.len_utf8())
22212        .sum::<usize>();
22213    let trailing_whitespace_len = buffer
22214        .chars_at(range.end)
22215        .take_while(|c| c.is_whitespace() && *c != '\n')
22216        .map(|c| c.len_utf8())
22217        .sum::<usize>();
22218    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22219
22220    language.brackets().any(|(pair, enabled)| {
22221        let pair_start = pair.start.trim_end();
22222        let pair_end = pair.end.trim_start();
22223
22224        enabled
22225            && pair.newline
22226            && buffer.contains_str_at(range.end, pair_end)
22227            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22228    })
22229}
22230
22231fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22232    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22233        [(buffer, range, _)] => (*buffer, range.clone()),
22234        _ => return false,
22235    };
22236    let pair = {
22237        let mut result: Option<BracketMatch> = None;
22238
22239        for pair in buffer
22240            .all_bracket_ranges(range.clone())
22241            .filter(move |pair| {
22242                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22243            })
22244        {
22245            let len = pair.close_range.end - pair.open_range.start;
22246
22247            if let Some(existing) = &result {
22248                let existing_len = existing.close_range.end - existing.open_range.start;
22249                if len > existing_len {
22250                    continue;
22251                }
22252            }
22253
22254            result = Some(pair);
22255        }
22256
22257        result
22258    };
22259    let Some(pair) = pair else {
22260        return false;
22261    };
22262    pair.newline_only
22263        && buffer
22264            .chars_for_range(pair.open_range.end..range.start)
22265            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22266            .all(|c| c.is_whitespace() && c != '\n')
22267}
22268
22269fn update_uncommitted_diff_for_buffer(
22270    editor: Entity<Editor>,
22271    project: &Entity<Project>,
22272    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22273    buffer: Entity<MultiBuffer>,
22274    cx: &mut App,
22275) -> Task<()> {
22276    let mut tasks = Vec::new();
22277    project.update(cx, |project, cx| {
22278        for buffer in buffers {
22279            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22280                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22281            }
22282        }
22283    });
22284    cx.spawn(async move |cx| {
22285        let diffs = future::join_all(tasks).await;
22286        if editor
22287            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22288            .unwrap_or(false)
22289        {
22290            return;
22291        }
22292
22293        buffer
22294            .update(cx, |buffer, cx| {
22295                for diff in diffs.into_iter().flatten() {
22296                    buffer.add_diff(diff, cx);
22297                }
22298            })
22299            .ok();
22300    })
22301}
22302
22303fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22304    let tab_size = tab_size.get() as usize;
22305    let mut width = offset;
22306
22307    for ch in text.chars() {
22308        width += if ch == '\t' {
22309            tab_size - (width % tab_size)
22310        } else {
22311            1
22312        };
22313    }
22314
22315    width - offset
22316}
22317
22318#[cfg(test)]
22319mod tests {
22320    use super::*;
22321
22322    #[test]
22323    fn test_string_size_with_expanded_tabs() {
22324        let nz = |val| NonZeroU32::new(val).unwrap();
22325        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22326        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22327        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22328        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22329        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22330        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22331        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22332        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22333    }
22334}
22335
22336/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22337struct WordBreakingTokenizer<'a> {
22338    input: &'a str,
22339}
22340
22341impl<'a> WordBreakingTokenizer<'a> {
22342    fn new(input: &'a str) -> Self {
22343        Self { input }
22344    }
22345}
22346
22347fn is_char_ideographic(ch: char) -> bool {
22348    use unicode_script::Script::*;
22349    use unicode_script::UnicodeScript;
22350    matches!(ch.script(), Han | Tangut | Yi)
22351}
22352
22353fn is_grapheme_ideographic(text: &str) -> bool {
22354    text.chars().any(is_char_ideographic)
22355}
22356
22357fn is_grapheme_whitespace(text: &str) -> bool {
22358    text.chars().any(|x| x.is_whitespace())
22359}
22360
22361fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22362    text.chars()
22363        .next()
22364        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22365}
22366
22367#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22368enum WordBreakToken<'a> {
22369    Word { token: &'a str, grapheme_len: usize },
22370    InlineWhitespace { token: &'a str, grapheme_len: usize },
22371    Newline,
22372}
22373
22374impl<'a> Iterator for WordBreakingTokenizer<'a> {
22375    /// Yields a span, the count of graphemes in the token, and whether it was
22376    /// whitespace. Note that it also breaks at word boundaries.
22377    type Item = WordBreakToken<'a>;
22378
22379    fn next(&mut self) -> Option<Self::Item> {
22380        use unicode_segmentation::UnicodeSegmentation;
22381        if self.input.is_empty() {
22382            return None;
22383        }
22384
22385        let mut iter = self.input.graphemes(true).peekable();
22386        let mut offset = 0;
22387        let mut grapheme_len = 0;
22388        if let Some(first_grapheme) = iter.next() {
22389            let is_newline = first_grapheme == "\n";
22390            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22391            offset += first_grapheme.len();
22392            grapheme_len += 1;
22393            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22394                if let Some(grapheme) = iter.peek().copied()
22395                    && should_stay_with_preceding_ideograph(grapheme)
22396                {
22397                    offset += grapheme.len();
22398                    grapheme_len += 1;
22399                }
22400            } else {
22401                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22402                let mut next_word_bound = words.peek().copied();
22403                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22404                    next_word_bound = words.next();
22405                }
22406                while let Some(grapheme) = iter.peek().copied() {
22407                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22408                        break;
22409                    };
22410                    if is_grapheme_whitespace(grapheme) != is_whitespace
22411                        || (grapheme == "\n") != is_newline
22412                    {
22413                        break;
22414                    };
22415                    offset += grapheme.len();
22416                    grapheme_len += 1;
22417                    iter.next();
22418                }
22419            }
22420            let token = &self.input[..offset];
22421            self.input = &self.input[offset..];
22422            if token == "\n" {
22423                Some(WordBreakToken::Newline)
22424            } else if is_whitespace {
22425                Some(WordBreakToken::InlineWhitespace {
22426                    token,
22427                    grapheme_len,
22428                })
22429            } else {
22430                Some(WordBreakToken::Word {
22431                    token,
22432                    grapheme_len,
22433                })
22434            }
22435        } else {
22436            None
22437        }
22438    }
22439}
22440
22441#[test]
22442fn test_word_breaking_tokenizer() {
22443    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22444        ("", &[]),
22445        ("  ", &[whitespace("  ", 2)]),
22446        ("Ʒ", &[word("Ʒ", 1)]),
22447        ("Ǽ", &[word("Ǽ", 1)]),
22448        ("", &[word("", 1)]),
22449        ("⋑⋑", &[word("⋑⋑", 2)]),
22450        (
22451            "原理,进而",
22452            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22453        ),
22454        (
22455            "hello world",
22456            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22457        ),
22458        (
22459            "hello, world",
22460            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22461        ),
22462        (
22463            "  hello world",
22464            &[
22465                whitespace("  ", 2),
22466                word("hello", 5),
22467                whitespace(" ", 1),
22468                word("world", 5),
22469            ],
22470        ),
22471        (
22472            "这是什么 \n 钢笔",
22473            &[
22474                word("", 1),
22475                word("", 1),
22476                word("", 1),
22477                word("", 1),
22478                whitespace(" ", 1),
22479                newline(),
22480                whitespace(" ", 1),
22481                word("", 1),
22482                word("", 1),
22483            ],
22484        ),
22485        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22486    ];
22487
22488    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22489        WordBreakToken::Word {
22490            token,
22491            grapheme_len,
22492        }
22493    }
22494
22495    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22496        WordBreakToken::InlineWhitespace {
22497            token,
22498            grapheme_len,
22499        }
22500    }
22501
22502    fn newline() -> WordBreakToken<'static> {
22503        WordBreakToken::Newline
22504    }
22505
22506    for (input, result) in tests {
22507        assert_eq!(
22508            WordBreakingTokenizer::new(input)
22509                .collect::<Vec<_>>()
22510                .as_slice(),
22511            *result,
22512        );
22513    }
22514}
22515
22516fn wrap_with_prefix(
22517    first_line_prefix: String,
22518    subsequent_lines_prefix: String,
22519    unwrapped_text: String,
22520    wrap_column: usize,
22521    tab_size: NonZeroU32,
22522    preserve_existing_whitespace: bool,
22523) -> String {
22524    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22525    let subsequent_lines_prefix_len =
22526        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22527    let mut wrapped_text = String::new();
22528    let mut current_line = first_line_prefix;
22529    let mut is_first_line = true;
22530
22531    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22532    let mut current_line_len = first_line_prefix_len;
22533    let mut in_whitespace = false;
22534    for token in tokenizer {
22535        let have_preceding_whitespace = in_whitespace;
22536        match token {
22537            WordBreakToken::Word {
22538                token,
22539                grapheme_len,
22540            } => {
22541                in_whitespace = false;
22542                let current_prefix_len = if is_first_line {
22543                    first_line_prefix_len
22544                } else {
22545                    subsequent_lines_prefix_len
22546                };
22547                if current_line_len + grapheme_len > wrap_column
22548                    && current_line_len != current_prefix_len
22549                {
22550                    wrapped_text.push_str(current_line.trim_end());
22551                    wrapped_text.push('\n');
22552                    is_first_line = false;
22553                    current_line = subsequent_lines_prefix.clone();
22554                    current_line_len = subsequent_lines_prefix_len;
22555                }
22556                current_line.push_str(token);
22557                current_line_len += grapheme_len;
22558            }
22559            WordBreakToken::InlineWhitespace {
22560                mut token,
22561                mut grapheme_len,
22562            } => {
22563                in_whitespace = true;
22564                if have_preceding_whitespace && !preserve_existing_whitespace {
22565                    continue;
22566                }
22567                if !preserve_existing_whitespace {
22568                    // Keep a single whitespace grapheme as-is
22569                    if let Some(first) =
22570                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22571                    {
22572                        token = first;
22573                    } else {
22574                        token = " ";
22575                    }
22576                    grapheme_len = 1;
22577                }
22578                let current_prefix_len = if is_first_line {
22579                    first_line_prefix_len
22580                } else {
22581                    subsequent_lines_prefix_len
22582                };
22583                if current_line_len + grapheme_len > wrap_column {
22584                    wrapped_text.push_str(current_line.trim_end());
22585                    wrapped_text.push('\n');
22586                    is_first_line = false;
22587                    current_line = subsequent_lines_prefix.clone();
22588                    current_line_len = subsequent_lines_prefix_len;
22589                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22590                    current_line.push_str(token);
22591                    current_line_len += grapheme_len;
22592                }
22593            }
22594            WordBreakToken::Newline => {
22595                in_whitespace = true;
22596                let current_prefix_len = if is_first_line {
22597                    first_line_prefix_len
22598                } else {
22599                    subsequent_lines_prefix_len
22600                };
22601                if preserve_existing_whitespace {
22602                    wrapped_text.push_str(current_line.trim_end());
22603                    wrapped_text.push('\n');
22604                    is_first_line = false;
22605                    current_line = subsequent_lines_prefix.clone();
22606                    current_line_len = subsequent_lines_prefix_len;
22607                } else if have_preceding_whitespace {
22608                    continue;
22609                } else if current_line_len + 1 > wrap_column
22610                    && current_line_len != current_prefix_len
22611                {
22612                    wrapped_text.push_str(current_line.trim_end());
22613                    wrapped_text.push('\n');
22614                    is_first_line = false;
22615                    current_line = subsequent_lines_prefix.clone();
22616                    current_line_len = subsequent_lines_prefix_len;
22617                } else if current_line_len != current_prefix_len {
22618                    current_line.push(' ');
22619                    current_line_len += 1;
22620                }
22621            }
22622        }
22623    }
22624
22625    if !current_line.is_empty() {
22626        wrapped_text.push_str(&current_line);
22627    }
22628    wrapped_text
22629}
22630
22631#[test]
22632fn test_wrap_with_prefix() {
22633    assert_eq!(
22634        wrap_with_prefix(
22635            "# ".to_string(),
22636            "# ".to_string(),
22637            "abcdefg".to_string(),
22638            4,
22639            NonZeroU32::new(4).unwrap(),
22640            false,
22641        ),
22642        "# abcdefg"
22643    );
22644    assert_eq!(
22645        wrap_with_prefix(
22646            "".to_string(),
22647            "".to_string(),
22648            "\thello world".to_string(),
22649            8,
22650            NonZeroU32::new(4).unwrap(),
22651            false,
22652        ),
22653        "hello\nworld"
22654    );
22655    assert_eq!(
22656        wrap_with_prefix(
22657            "// ".to_string(),
22658            "// ".to_string(),
22659            "xx \nyy zz aa bb cc".to_string(),
22660            12,
22661            NonZeroU32::new(4).unwrap(),
22662            false,
22663        ),
22664        "// xx yy zz\n// aa bb cc"
22665    );
22666    assert_eq!(
22667        wrap_with_prefix(
22668            String::new(),
22669            String::new(),
22670            "这是什么 \n 钢笔".to_string(),
22671            3,
22672            NonZeroU32::new(4).unwrap(),
22673            false,
22674        ),
22675        "这是什\n么 钢\n"
22676    );
22677    assert_eq!(
22678        wrap_with_prefix(
22679            String::new(),
22680            String::new(),
22681            format!("foo{}bar", '\u{2009}'), // thin space
22682            80,
22683            NonZeroU32::new(4).unwrap(),
22684            false,
22685        ),
22686        format!("foo{}bar", '\u{2009}')
22687    );
22688}
22689
22690pub trait CollaborationHub {
22691    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22692    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22693    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22694}
22695
22696impl CollaborationHub for Entity<Project> {
22697    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22698        self.read(cx).collaborators()
22699    }
22700
22701    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22702        self.read(cx).user_store().read(cx).participant_indices()
22703    }
22704
22705    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22706        let this = self.read(cx);
22707        let user_ids = this.collaborators().values().map(|c| c.user_id);
22708        this.user_store().read(cx).participant_names(user_ids, cx)
22709    }
22710}
22711
22712pub trait SemanticsProvider {
22713    fn hover(
22714        &self,
22715        buffer: &Entity<Buffer>,
22716        position: text::Anchor,
22717        cx: &mut App,
22718    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22719
22720    fn inline_values(
22721        &self,
22722        buffer_handle: Entity<Buffer>,
22723        range: Range<text::Anchor>,
22724        cx: &mut App,
22725    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22726
22727    fn applicable_inlay_chunks(
22728        &self,
22729        buffer: &Entity<Buffer>,
22730        ranges: &[Range<text::Anchor>],
22731        cx: &mut App,
22732    ) -> Vec<Range<BufferRow>>;
22733
22734    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22735
22736    fn inlay_hints(
22737        &self,
22738        invalidate: InvalidationStrategy,
22739        buffer: Entity<Buffer>,
22740        ranges: Vec<Range<text::Anchor>>,
22741        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22742        cx: &mut App,
22743    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22744
22745    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22746
22747    fn document_highlights(
22748        &self,
22749        buffer: &Entity<Buffer>,
22750        position: text::Anchor,
22751        cx: &mut App,
22752    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22753
22754    fn definitions(
22755        &self,
22756        buffer: &Entity<Buffer>,
22757        position: text::Anchor,
22758        kind: GotoDefinitionKind,
22759        cx: &mut App,
22760    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22761
22762    fn range_for_rename(
22763        &self,
22764        buffer: &Entity<Buffer>,
22765        position: text::Anchor,
22766        cx: &mut App,
22767    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22768
22769    fn perform_rename(
22770        &self,
22771        buffer: &Entity<Buffer>,
22772        position: text::Anchor,
22773        new_name: String,
22774        cx: &mut App,
22775    ) -> Option<Task<Result<ProjectTransaction>>>;
22776}
22777
22778pub trait CompletionProvider {
22779    fn completions(
22780        &self,
22781        excerpt_id: ExcerptId,
22782        buffer: &Entity<Buffer>,
22783        buffer_position: text::Anchor,
22784        trigger: CompletionContext,
22785        window: &mut Window,
22786        cx: &mut Context<Editor>,
22787    ) -> Task<Result<Vec<CompletionResponse>>>;
22788
22789    fn resolve_completions(
22790        &self,
22791        _buffer: Entity<Buffer>,
22792        _completion_indices: Vec<usize>,
22793        _completions: Rc<RefCell<Box<[Completion]>>>,
22794        _cx: &mut Context<Editor>,
22795    ) -> Task<Result<bool>> {
22796        Task::ready(Ok(false))
22797    }
22798
22799    fn apply_additional_edits_for_completion(
22800        &self,
22801        _buffer: Entity<Buffer>,
22802        _completions: Rc<RefCell<Box<[Completion]>>>,
22803        _completion_index: usize,
22804        _push_to_history: bool,
22805        _cx: &mut Context<Editor>,
22806    ) -> Task<Result<Option<language::Transaction>>> {
22807        Task::ready(Ok(None))
22808    }
22809
22810    fn is_completion_trigger(
22811        &self,
22812        buffer: &Entity<Buffer>,
22813        position: language::Anchor,
22814        text: &str,
22815        trigger_in_words: bool,
22816        menu_is_open: bool,
22817        cx: &mut Context<Editor>,
22818    ) -> bool;
22819
22820    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22821
22822    fn sort_completions(&self) -> bool {
22823        true
22824    }
22825
22826    fn filter_completions(&self) -> bool {
22827        true
22828    }
22829}
22830
22831pub trait CodeActionProvider {
22832    fn id(&self) -> Arc<str>;
22833
22834    fn code_actions(
22835        &self,
22836        buffer: &Entity<Buffer>,
22837        range: Range<text::Anchor>,
22838        window: &mut Window,
22839        cx: &mut App,
22840    ) -> Task<Result<Vec<CodeAction>>>;
22841
22842    fn apply_code_action(
22843        &self,
22844        buffer_handle: Entity<Buffer>,
22845        action: CodeAction,
22846        excerpt_id: ExcerptId,
22847        push_to_history: bool,
22848        window: &mut Window,
22849        cx: &mut App,
22850    ) -> Task<Result<ProjectTransaction>>;
22851}
22852
22853impl CodeActionProvider for Entity<Project> {
22854    fn id(&self) -> Arc<str> {
22855        "project".into()
22856    }
22857
22858    fn code_actions(
22859        &self,
22860        buffer: &Entity<Buffer>,
22861        range: Range<text::Anchor>,
22862        _window: &mut Window,
22863        cx: &mut App,
22864    ) -> Task<Result<Vec<CodeAction>>> {
22865        self.update(cx, |project, cx| {
22866            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22867            let code_actions = project.code_actions(buffer, range, None, cx);
22868            cx.background_spawn(async move {
22869                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22870                Ok(code_lens_actions
22871                    .context("code lens fetch")?
22872                    .into_iter()
22873                    .flatten()
22874                    .chain(
22875                        code_actions
22876                            .context("code action fetch")?
22877                            .into_iter()
22878                            .flatten(),
22879                    )
22880                    .collect())
22881            })
22882        })
22883    }
22884
22885    fn apply_code_action(
22886        &self,
22887        buffer_handle: Entity<Buffer>,
22888        action: CodeAction,
22889        _excerpt_id: ExcerptId,
22890        push_to_history: bool,
22891        _window: &mut Window,
22892        cx: &mut App,
22893    ) -> Task<Result<ProjectTransaction>> {
22894        self.update(cx, |project, cx| {
22895            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22896        })
22897    }
22898}
22899
22900fn snippet_completions(
22901    project: &Project,
22902    buffer: &Entity<Buffer>,
22903    buffer_position: text::Anchor,
22904    cx: &mut App,
22905) -> Task<Result<CompletionResponse>> {
22906    let languages = buffer.read(cx).languages_at(buffer_position);
22907    let snippet_store = project.snippets().read(cx);
22908
22909    let scopes: Vec<_> = languages
22910        .iter()
22911        .filter_map(|language| {
22912            let language_name = language.lsp_id();
22913            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22914
22915            if snippets.is_empty() {
22916                None
22917            } else {
22918                Some((language.default_scope(), snippets))
22919            }
22920        })
22921        .collect();
22922
22923    if scopes.is_empty() {
22924        return Task::ready(Ok(CompletionResponse {
22925            completions: vec![],
22926            display_options: CompletionDisplayOptions::default(),
22927            is_incomplete: false,
22928        }));
22929    }
22930
22931    let snapshot = buffer.read(cx).text_snapshot();
22932    let executor = cx.background_executor().clone();
22933
22934    cx.background_spawn(async move {
22935        let mut is_incomplete = false;
22936        let mut completions: Vec<Completion> = Vec::new();
22937        for (scope, snippets) in scopes.into_iter() {
22938            let classifier =
22939                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22940
22941            const MAX_WORD_PREFIX_LEN: usize = 128;
22942            let last_word: String = snapshot
22943                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22944                .take(MAX_WORD_PREFIX_LEN)
22945                .take_while(|c| classifier.is_word(*c))
22946                .collect::<String>()
22947                .chars()
22948                .rev()
22949                .collect();
22950
22951            if last_word.is_empty() {
22952                return Ok(CompletionResponse {
22953                    completions: vec![],
22954                    display_options: CompletionDisplayOptions::default(),
22955                    is_incomplete: true,
22956                });
22957            }
22958
22959            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22960            let to_lsp = |point: &text::Anchor| {
22961                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22962                point_to_lsp(end)
22963            };
22964            let lsp_end = to_lsp(&buffer_position);
22965
22966            let candidates = snippets
22967                .iter()
22968                .enumerate()
22969                .flat_map(|(ix, snippet)| {
22970                    snippet
22971                        .prefix
22972                        .iter()
22973                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22974                })
22975                .collect::<Vec<StringMatchCandidate>>();
22976
22977            const MAX_RESULTS: usize = 100;
22978            let mut matches = fuzzy::match_strings(
22979                &candidates,
22980                &last_word,
22981                last_word.chars().any(|c| c.is_uppercase()),
22982                true,
22983                MAX_RESULTS,
22984                &Default::default(),
22985                executor.clone(),
22986            )
22987            .await;
22988
22989            if matches.len() >= MAX_RESULTS {
22990                is_incomplete = true;
22991            }
22992
22993            // Remove all candidates where the query's start does not match the start of any word in the candidate
22994            if let Some(query_start) = last_word.chars().next() {
22995                matches.retain(|string_match| {
22996                    split_words(&string_match.string).any(|word| {
22997                        // Check that the first codepoint of the word as lowercase matches the first
22998                        // codepoint of the query as lowercase
22999                        word.chars()
23000                            .flat_map(|codepoint| codepoint.to_lowercase())
23001                            .zip(query_start.to_lowercase())
23002                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23003                    })
23004                });
23005            }
23006
23007            let matched_strings = matches
23008                .into_iter()
23009                .map(|m| m.string)
23010                .collect::<HashSet<_>>();
23011
23012            completions.extend(snippets.iter().filter_map(|snippet| {
23013                let matching_prefix = snippet
23014                    .prefix
23015                    .iter()
23016                    .find(|prefix| matched_strings.contains(*prefix))?;
23017                let start = as_offset - last_word.len();
23018                let start = snapshot.anchor_before(start);
23019                let range = start..buffer_position;
23020                let lsp_start = to_lsp(&start);
23021                let lsp_range = lsp::Range {
23022                    start: lsp_start,
23023                    end: lsp_end,
23024                };
23025                Some(Completion {
23026                    replace_range: range,
23027                    new_text: snippet.body.clone(),
23028                    source: CompletionSource::Lsp {
23029                        insert_range: None,
23030                        server_id: LanguageServerId(usize::MAX),
23031                        resolved: true,
23032                        lsp_completion: Box::new(lsp::CompletionItem {
23033                            label: snippet.prefix.first().unwrap().clone(),
23034                            kind: Some(CompletionItemKind::SNIPPET),
23035                            label_details: snippet.description.as_ref().map(|description| {
23036                                lsp::CompletionItemLabelDetails {
23037                                    detail: Some(description.clone()),
23038                                    description: None,
23039                                }
23040                            }),
23041                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23042                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23043                                lsp::InsertReplaceEdit {
23044                                    new_text: snippet.body.clone(),
23045                                    insert: lsp_range,
23046                                    replace: lsp_range,
23047                                },
23048                            )),
23049                            filter_text: Some(snippet.body.clone()),
23050                            sort_text: Some(char::MAX.to_string()),
23051                            ..lsp::CompletionItem::default()
23052                        }),
23053                        lsp_defaults: None,
23054                    },
23055                    label: CodeLabel::plain(matching_prefix.clone(), None),
23056                    icon_path: None,
23057                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23058                        single_line: snippet.name.clone().into(),
23059                        plain_text: snippet
23060                            .description
23061                            .clone()
23062                            .map(|description| description.into()),
23063                    }),
23064                    insert_text_mode: None,
23065                    confirm: None,
23066                })
23067            }))
23068        }
23069
23070        Ok(CompletionResponse {
23071            completions,
23072            display_options: CompletionDisplayOptions::default(),
23073            is_incomplete,
23074        })
23075    })
23076}
23077
23078impl CompletionProvider for Entity<Project> {
23079    fn completions(
23080        &self,
23081        _excerpt_id: ExcerptId,
23082        buffer: &Entity<Buffer>,
23083        buffer_position: text::Anchor,
23084        options: CompletionContext,
23085        _window: &mut Window,
23086        cx: &mut Context<Editor>,
23087    ) -> Task<Result<Vec<CompletionResponse>>> {
23088        self.update(cx, |project, cx| {
23089            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23090            let project_completions = project.completions(buffer, buffer_position, options, cx);
23091            cx.background_spawn(async move {
23092                let mut responses = project_completions.await?;
23093                let snippets = snippets.await?;
23094                if !snippets.completions.is_empty() {
23095                    responses.push(snippets);
23096                }
23097                Ok(responses)
23098            })
23099        })
23100    }
23101
23102    fn resolve_completions(
23103        &self,
23104        buffer: Entity<Buffer>,
23105        completion_indices: Vec<usize>,
23106        completions: Rc<RefCell<Box<[Completion]>>>,
23107        cx: &mut Context<Editor>,
23108    ) -> Task<Result<bool>> {
23109        self.update(cx, |project, cx| {
23110            project.lsp_store().update(cx, |lsp_store, cx| {
23111                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23112            })
23113        })
23114    }
23115
23116    fn apply_additional_edits_for_completion(
23117        &self,
23118        buffer: Entity<Buffer>,
23119        completions: Rc<RefCell<Box<[Completion]>>>,
23120        completion_index: usize,
23121        push_to_history: bool,
23122        cx: &mut Context<Editor>,
23123    ) -> Task<Result<Option<language::Transaction>>> {
23124        self.update(cx, |project, cx| {
23125            project.lsp_store().update(cx, |lsp_store, cx| {
23126                lsp_store.apply_additional_edits_for_completion(
23127                    buffer,
23128                    completions,
23129                    completion_index,
23130                    push_to_history,
23131                    cx,
23132                )
23133            })
23134        })
23135    }
23136
23137    fn is_completion_trigger(
23138        &self,
23139        buffer: &Entity<Buffer>,
23140        position: language::Anchor,
23141        text: &str,
23142        trigger_in_words: bool,
23143        menu_is_open: bool,
23144        cx: &mut Context<Editor>,
23145    ) -> bool {
23146        let mut chars = text.chars();
23147        let char = if let Some(char) = chars.next() {
23148            char
23149        } else {
23150            return false;
23151        };
23152        if chars.next().is_some() {
23153            return false;
23154        }
23155
23156        let buffer = buffer.read(cx);
23157        let snapshot = buffer.snapshot();
23158        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23159            return false;
23160        }
23161        let classifier = snapshot
23162            .char_classifier_at(position)
23163            .scope_context(Some(CharScopeContext::Completion));
23164        if trigger_in_words && classifier.is_word(char) {
23165            return true;
23166        }
23167
23168        buffer.completion_triggers().contains(text)
23169    }
23170}
23171
23172impl SemanticsProvider for Entity<Project> {
23173    fn hover(
23174        &self,
23175        buffer: &Entity<Buffer>,
23176        position: text::Anchor,
23177        cx: &mut App,
23178    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23179        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23180    }
23181
23182    fn document_highlights(
23183        &self,
23184        buffer: &Entity<Buffer>,
23185        position: text::Anchor,
23186        cx: &mut App,
23187    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23188        Some(self.update(cx, |project, cx| {
23189            project.document_highlights(buffer, position, cx)
23190        }))
23191    }
23192
23193    fn definitions(
23194        &self,
23195        buffer: &Entity<Buffer>,
23196        position: text::Anchor,
23197        kind: GotoDefinitionKind,
23198        cx: &mut App,
23199    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23200        Some(self.update(cx, |project, cx| match kind {
23201            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23202            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23203            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23204            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23205        }))
23206    }
23207
23208    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23209        self.update(cx, |project, cx| {
23210            if project
23211                .active_debug_session(cx)
23212                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23213            {
23214                return true;
23215            }
23216
23217            buffer.update(cx, |buffer, cx| {
23218                project.any_language_server_supports_inlay_hints(buffer, cx)
23219            })
23220        })
23221    }
23222
23223    fn inline_values(
23224        &self,
23225        buffer_handle: Entity<Buffer>,
23226        range: Range<text::Anchor>,
23227        cx: &mut App,
23228    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23229        self.update(cx, |project, cx| {
23230            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23231
23232            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23233        })
23234    }
23235
23236    fn applicable_inlay_chunks(
23237        &self,
23238        buffer: &Entity<Buffer>,
23239        ranges: &[Range<text::Anchor>],
23240        cx: &mut App,
23241    ) -> Vec<Range<BufferRow>> {
23242        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23243            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23244        })
23245    }
23246
23247    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23248        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23249            lsp_store.invalidate_inlay_hints(for_buffers)
23250        });
23251    }
23252
23253    fn inlay_hints(
23254        &self,
23255        invalidate: InvalidationStrategy,
23256        buffer: Entity<Buffer>,
23257        ranges: Vec<Range<text::Anchor>>,
23258        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23259        cx: &mut App,
23260    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23261        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23262            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23263        }))
23264    }
23265
23266    fn range_for_rename(
23267        &self,
23268        buffer: &Entity<Buffer>,
23269        position: text::Anchor,
23270        cx: &mut App,
23271    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23272        Some(self.update(cx, |project, cx| {
23273            let buffer = buffer.clone();
23274            let task = project.prepare_rename(buffer.clone(), position, cx);
23275            cx.spawn(async move |_, cx| {
23276                Ok(match task.await? {
23277                    PrepareRenameResponse::Success(range) => Some(range),
23278                    PrepareRenameResponse::InvalidPosition => None,
23279                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23280                        // Fallback on using TreeSitter info to determine identifier range
23281                        buffer.read_with(cx, |buffer, _| {
23282                            let snapshot = buffer.snapshot();
23283                            let (range, kind) = snapshot.surrounding_word(position, None);
23284                            if kind != Some(CharKind::Word) {
23285                                return None;
23286                            }
23287                            Some(
23288                                snapshot.anchor_before(range.start)
23289                                    ..snapshot.anchor_after(range.end),
23290                            )
23291                        })?
23292                    }
23293                })
23294            })
23295        }))
23296    }
23297
23298    fn perform_rename(
23299        &self,
23300        buffer: &Entity<Buffer>,
23301        position: text::Anchor,
23302        new_name: String,
23303        cx: &mut App,
23304    ) -> Option<Task<Result<ProjectTransaction>>> {
23305        Some(self.update(cx, |project, cx| {
23306            project.perform_rename(buffer.clone(), position, new_name, cx)
23307        }))
23308    }
23309}
23310
23311fn consume_contiguous_rows(
23312    contiguous_row_selections: &mut Vec<Selection<Point>>,
23313    selection: &Selection<Point>,
23314    display_map: &DisplaySnapshot,
23315    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23316) -> (MultiBufferRow, MultiBufferRow) {
23317    contiguous_row_selections.push(selection.clone());
23318    let start_row = starting_row(selection, display_map);
23319    let mut end_row = ending_row(selection, display_map);
23320
23321    while let Some(next_selection) = selections.peek() {
23322        if next_selection.start.row <= end_row.0 {
23323            end_row = ending_row(next_selection, display_map);
23324            contiguous_row_selections.push(selections.next().unwrap().clone());
23325        } else {
23326            break;
23327        }
23328    }
23329    (start_row, end_row)
23330}
23331
23332fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23333    if selection.start.column > 0 {
23334        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23335    } else {
23336        MultiBufferRow(selection.start.row)
23337    }
23338}
23339
23340fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23341    if next_selection.end.column > 0 || next_selection.is_empty() {
23342        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23343    } else {
23344        MultiBufferRow(next_selection.end.row)
23345    }
23346}
23347
23348impl EditorSnapshot {
23349    pub fn remote_selections_in_range<'a>(
23350        &'a self,
23351        range: &'a Range<Anchor>,
23352        collaboration_hub: &dyn CollaborationHub,
23353        cx: &'a App,
23354    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23355        let participant_names = collaboration_hub.user_names(cx);
23356        let participant_indices = collaboration_hub.user_participant_indices(cx);
23357        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23358        let collaborators_by_replica_id = collaborators_by_peer_id
23359            .values()
23360            .map(|collaborator| (collaborator.replica_id, collaborator))
23361            .collect::<HashMap<_, _>>();
23362        self.buffer_snapshot()
23363            .selections_in_range(range, false)
23364            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23365                if replica_id == ReplicaId::AGENT {
23366                    Some(RemoteSelection {
23367                        replica_id,
23368                        selection,
23369                        cursor_shape,
23370                        line_mode,
23371                        collaborator_id: CollaboratorId::Agent,
23372                        user_name: Some("Agent".into()),
23373                        color: cx.theme().players().agent(),
23374                    })
23375                } else {
23376                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23377                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23378                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23379                    Some(RemoteSelection {
23380                        replica_id,
23381                        selection,
23382                        cursor_shape,
23383                        line_mode,
23384                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23385                        user_name,
23386                        color: if let Some(index) = participant_index {
23387                            cx.theme().players().color_for_participant(index.0)
23388                        } else {
23389                            cx.theme().players().absent()
23390                        },
23391                    })
23392                }
23393            })
23394    }
23395
23396    pub fn hunks_for_ranges(
23397        &self,
23398        ranges: impl IntoIterator<Item = Range<Point>>,
23399    ) -> Vec<MultiBufferDiffHunk> {
23400        let mut hunks = Vec::new();
23401        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23402            HashMap::default();
23403        for query_range in ranges {
23404            let query_rows =
23405                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23406            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23407                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23408            ) {
23409                // Include deleted hunks that are adjacent to the query range, because
23410                // otherwise they would be missed.
23411                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23412                if hunk.status().is_deleted() {
23413                    intersects_range |= hunk.row_range.start == query_rows.end;
23414                    intersects_range |= hunk.row_range.end == query_rows.start;
23415                }
23416                if intersects_range {
23417                    if !processed_buffer_rows
23418                        .entry(hunk.buffer_id)
23419                        .or_default()
23420                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23421                    {
23422                        continue;
23423                    }
23424                    hunks.push(hunk);
23425                }
23426            }
23427        }
23428
23429        hunks
23430    }
23431
23432    fn display_diff_hunks_for_rows<'a>(
23433        &'a self,
23434        display_rows: Range<DisplayRow>,
23435        folded_buffers: &'a HashSet<BufferId>,
23436    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23437        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23438        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23439
23440        self.buffer_snapshot()
23441            .diff_hunks_in_range(buffer_start..buffer_end)
23442            .filter_map(|hunk| {
23443                if folded_buffers.contains(&hunk.buffer_id) {
23444                    return None;
23445                }
23446
23447                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23448                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23449
23450                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23451                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23452
23453                let display_hunk = if hunk_display_start.column() != 0 {
23454                    DisplayDiffHunk::Folded {
23455                        display_row: hunk_display_start.row(),
23456                    }
23457                } else {
23458                    let mut end_row = hunk_display_end.row();
23459                    if hunk_display_end.column() > 0 {
23460                        end_row.0 += 1;
23461                    }
23462                    let is_created_file = hunk.is_created_file();
23463                    DisplayDiffHunk::Unfolded {
23464                        status: hunk.status(),
23465                        diff_base_byte_range: hunk.diff_base_byte_range,
23466                        display_row_range: hunk_display_start.row()..end_row,
23467                        multi_buffer_range: Anchor::range_in_buffer(
23468                            hunk.excerpt_id,
23469                            hunk.buffer_id,
23470                            hunk.buffer_range,
23471                        ),
23472                        is_created_file,
23473                    }
23474                };
23475
23476                Some(display_hunk)
23477            })
23478    }
23479
23480    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23481        self.display_snapshot
23482            .buffer_snapshot()
23483            .language_at(position)
23484    }
23485
23486    pub fn is_focused(&self) -> bool {
23487        self.is_focused
23488    }
23489
23490    pub fn placeholder_text(&self) -> Option<String> {
23491        self.placeholder_display_snapshot
23492            .as_ref()
23493            .map(|display_map| display_map.text())
23494    }
23495
23496    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23497        self.scroll_anchor.scroll_position(&self.display_snapshot)
23498    }
23499
23500    fn gutter_dimensions(
23501        &self,
23502        font_id: FontId,
23503        font_size: Pixels,
23504        max_line_number_width: Pixels,
23505        cx: &App,
23506    ) -> Option<GutterDimensions> {
23507        if !self.show_gutter {
23508            return None;
23509        }
23510
23511        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23512        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23513
23514        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23515            matches!(
23516                ProjectSettings::get_global(cx).git.git_gutter,
23517                GitGutterSetting::TrackedFiles
23518            )
23519        });
23520        let gutter_settings = EditorSettings::get_global(cx).gutter;
23521        let show_line_numbers = self
23522            .show_line_numbers
23523            .unwrap_or(gutter_settings.line_numbers);
23524        let line_gutter_width = if show_line_numbers {
23525            // Avoid flicker-like gutter resizes when the line number gains another digit by
23526            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23527            let min_width_for_number_on_gutter =
23528                ch_advance * gutter_settings.min_line_number_digits as f32;
23529            max_line_number_width.max(min_width_for_number_on_gutter)
23530        } else {
23531            0.0.into()
23532        };
23533
23534        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23535        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23536
23537        let git_blame_entries_width =
23538            self.git_blame_gutter_max_author_length
23539                .map(|max_author_length| {
23540                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23541                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23542
23543                    /// The number of characters to dedicate to gaps and margins.
23544                    const SPACING_WIDTH: usize = 4;
23545
23546                    let max_char_count = max_author_length.min(renderer.max_author_length())
23547                        + ::git::SHORT_SHA_LENGTH
23548                        + MAX_RELATIVE_TIMESTAMP.len()
23549                        + SPACING_WIDTH;
23550
23551                    ch_advance * max_char_count
23552                });
23553
23554        let is_singleton = self.buffer_snapshot().is_singleton();
23555
23556        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23557        left_padding += if !is_singleton {
23558            ch_width * 4.0
23559        } else if show_runnables || show_breakpoints {
23560            ch_width * 3.0
23561        } else if show_git_gutter && show_line_numbers {
23562            ch_width * 2.0
23563        } else if show_git_gutter || show_line_numbers {
23564            ch_width
23565        } else {
23566            px(0.)
23567        };
23568
23569        let shows_folds = is_singleton && gutter_settings.folds;
23570
23571        let right_padding = if shows_folds && show_line_numbers {
23572            ch_width * 4.0
23573        } else if shows_folds || (!is_singleton && show_line_numbers) {
23574            ch_width * 3.0
23575        } else if show_line_numbers {
23576            ch_width
23577        } else {
23578            px(0.)
23579        };
23580
23581        Some(GutterDimensions {
23582            left_padding,
23583            right_padding,
23584            width: line_gutter_width + left_padding + right_padding,
23585            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23586            git_blame_entries_width,
23587        })
23588    }
23589
23590    pub fn render_crease_toggle(
23591        &self,
23592        buffer_row: MultiBufferRow,
23593        row_contains_cursor: bool,
23594        editor: Entity<Editor>,
23595        window: &mut Window,
23596        cx: &mut App,
23597    ) -> Option<AnyElement> {
23598        let folded = self.is_line_folded(buffer_row);
23599        let mut is_foldable = false;
23600
23601        if let Some(crease) = self
23602            .crease_snapshot
23603            .query_row(buffer_row, self.buffer_snapshot())
23604        {
23605            is_foldable = true;
23606            match crease {
23607                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23608                    if let Some(render_toggle) = render_toggle {
23609                        let toggle_callback =
23610                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23611                                if folded {
23612                                    editor.update(cx, |editor, cx| {
23613                                        editor.fold_at(buffer_row, window, cx)
23614                                    });
23615                                } else {
23616                                    editor.update(cx, |editor, cx| {
23617                                        editor.unfold_at(buffer_row, window, cx)
23618                                    });
23619                                }
23620                            });
23621                        return Some((render_toggle)(
23622                            buffer_row,
23623                            folded,
23624                            toggle_callback,
23625                            window,
23626                            cx,
23627                        ));
23628                    }
23629                }
23630            }
23631        }
23632
23633        is_foldable |= self.starts_indent(buffer_row);
23634
23635        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23636            Some(
23637                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23638                    .toggle_state(folded)
23639                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23640                        if folded {
23641                            this.unfold_at(buffer_row, window, cx);
23642                        } else {
23643                            this.fold_at(buffer_row, window, cx);
23644                        }
23645                    }))
23646                    .into_any_element(),
23647            )
23648        } else {
23649            None
23650        }
23651    }
23652
23653    pub fn render_crease_trailer(
23654        &self,
23655        buffer_row: MultiBufferRow,
23656        window: &mut Window,
23657        cx: &mut App,
23658    ) -> Option<AnyElement> {
23659        let folded = self.is_line_folded(buffer_row);
23660        if let Crease::Inline { render_trailer, .. } = self
23661            .crease_snapshot
23662            .query_row(buffer_row, self.buffer_snapshot())?
23663        {
23664            let render_trailer = render_trailer.as_ref()?;
23665            Some(render_trailer(buffer_row, folded, window, cx))
23666        } else {
23667            None
23668        }
23669    }
23670}
23671
23672impl Deref for EditorSnapshot {
23673    type Target = DisplaySnapshot;
23674
23675    fn deref(&self) -> &Self::Target {
23676        &self.display_snapshot
23677    }
23678}
23679
23680#[derive(Clone, Debug, PartialEq, Eq)]
23681pub enum EditorEvent {
23682    InputIgnored {
23683        text: Arc<str>,
23684    },
23685    InputHandled {
23686        utf16_range_to_replace: Option<Range<isize>>,
23687        text: Arc<str>,
23688    },
23689    ExcerptsAdded {
23690        buffer: Entity<Buffer>,
23691        predecessor: ExcerptId,
23692        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23693    },
23694    ExcerptsRemoved {
23695        ids: Vec<ExcerptId>,
23696        removed_buffer_ids: Vec<BufferId>,
23697    },
23698    BufferFoldToggled {
23699        ids: Vec<ExcerptId>,
23700        folded: bool,
23701    },
23702    ExcerptsEdited {
23703        ids: Vec<ExcerptId>,
23704    },
23705    ExcerptsExpanded {
23706        ids: Vec<ExcerptId>,
23707    },
23708    BufferEdited,
23709    Edited {
23710        transaction_id: clock::Lamport,
23711    },
23712    Reparsed(BufferId),
23713    Focused,
23714    FocusedIn,
23715    Blurred,
23716    DirtyChanged,
23717    Saved,
23718    TitleChanged,
23719    SelectionsChanged {
23720        local: bool,
23721    },
23722    ScrollPositionChanged {
23723        local: bool,
23724        autoscroll: bool,
23725    },
23726    TransactionUndone {
23727        transaction_id: clock::Lamport,
23728    },
23729    TransactionBegun {
23730        transaction_id: clock::Lamport,
23731    },
23732    CursorShapeChanged,
23733    BreadcrumbsChanged,
23734    PushedToNavHistory {
23735        anchor: Anchor,
23736        is_deactivate: bool,
23737    },
23738}
23739
23740impl EventEmitter<EditorEvent> for Editor {}
23741
23742impl Focusable for Editor {
23743    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23744        self.focus_handle.clone()
23745    }
23746}
23747
23748impl Render for Editor {
23749    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23750        let settings = ThemeSettings::get_global(cx);
23751
23752        let mut text_style = match self.mode {
23753            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23754                color: cx.theme().colors().editor_foreground,
23755                font_family: settings.ui_font.family.clone(),
23756                font_features: settings.ui_font.features.clone(),
23757                font_fallbacks: settings.ui_font.fallbacks.clone(),
23758                font_size: rems(0.875).into(),
23759                font_weight: settings.ui_font.weight,
23760                line_height: relative(settings.buffer_line_height.value()),
23761                ..Default::default()
23762            },
23763            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23764                color: cx.theme().colors().editor_foreground,
23765                font_family: settings.buffer_font.family.clone(),
23766                font_features: settings.buffer_font.features.clone(),
23767                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23768                font_size: settings.buffer_font_size(cx).into(),
23769                font_weight: settings.buffer_font.weight,
23770                line_height: relative(settings.buffer_line_height.value()),
23771                ..Default::default()
23772            },
23773        };
23774        if let Some(text_style_refinement) = &self.text_style_refinement {
23775            text_style.refine(text_style_refinement)
23776        }
23777
23778        let background = match self.mode {
23779            EditorMode::SingleLine => cx.theme().system().transparent,
23780            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23781            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23782            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23783        };
23784
23785        EditorElement::new(
23786            &cx.entity(),
23787            EditorStyle {
23788                background,
23789                border: cx.theme().colors().border,
23790                local_player: cx.theme().players().local(),
23791                text: text_style,
23792                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23793                syntax: cx.theme().syntax().clone(),
23794                status: cx.theme().status().clone(),
23795                inlay_hints_style: make_inlay_hints_style(cx),
23796                edit_prediction_styles: make_suggestion_styles(cx),
23797                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23798                show_underlines: self.diagnostics_enabled(),
23799            },
23800        )
23801    }
23802}
23803
23804impl EntityInputHandler for Editor {
23805    fn text_for_range(
23806        &mut self,
23807        range_utf16: Range<usize>,
23808        adjusted_range: &mut Option<Range<usize>>,
23809        _: &mut Window,
23810        cx: &mut Context<Self>,
23811    ) -> Option<String> {
23812        let snapshot = self.buffer.read(cx).read(cx);
23813        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23814        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23815        if (start.0..end.0) != range_utf16 {
23816            adjusted_range.replace(start.0..end.0);
23817        }
23818        Some(snapshot.text_for_range(start..end).collect())
23819    }
23820
23821    fn selected_text_range(
23822        &mut self,
23823        ignore_disabled_input: bool,
23824        _: &mut Window,
23825        cx: &mut Context<Self>,
23826    ) -> Option<UTF16Selection> {
23827        // Prevent the IME menu from appearing when holding down an alphabetic key
23828        // while input is disabled.
23829        if !ignore_disabled_input && !self.input_enabled {
23830            return None;
23831        }
23832
23833        let selection = self
23834            .selections
23835            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23836        let range = selection.range();
23837
23838        Some(UTF16Selection {
23839            range: range.start.0..range.end.0,
23840            reversed: selection.reversed,
23841        })
23842    }
23843
23844    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23845        let snapshot = self.buffer.read(cx).read(cx);
23846        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23847        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23848    }
23849
23850    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23851        self.clear_highlights::<InputComposition>(cx);
23852        self.ime_transaction.take();
23853    }
23854
23855    fn replace_text_in_range(
23856        &mut self,
23857        range_utf16: Option<Range<usize>>,
23858        text: &str,
23859        window: &mut Window,
23860        cx: &mut Context<Self>,
23861    ) {
23862        if !self.input_enabled {
23863            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23864            return;
23865        }
23866
23867        self.transact(window, cx, |this, window, cx| {
23868            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23869                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23870                Some(this.selection_replacement_ranges(range_utf16, cx))
23871            } else {
23872                this.marked_text_ranges(cx)
23873            };
23874
23875            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23876                let newest_selection_id = this.selections.newest_anchor().id;
23877                this.selections
23878                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23879                    .iter()
23880                    .zip(ranges_to_replace.iter())
23881                    .find_map(|(selection, range)| {
23882                        if selection.id == newest_selection_id {
23883                            Some(
23884                                (range.start.0 as isize - selection.head().0 as isize)
23885                                    ..(range.end.0 as isize - selection.head().0 as isize),
23886                            )
23887                        } else {
23888                            None
23889                        }
23890                    })
23891            });
23892
23893            cx.emit(EditorEvent::InputHandled {
23894                utf16_range_to_replace: range_to_replace,
23895                text: text.into(),
23896            });
23897
23898            if let Some(new_selected_ranges) = new_selected_ranges {
23899                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23900                    selections.select_ranges(new_selected_ranges)
23901                });
23902                this.backspace(&Default::default(), window, cx);
23903            }
23904
23905            this.handle_input(text, window, cx);
23906        });
23907
23908        if let Some(transaction) = self.ime_transaction {
23909            self.buffer.update(cx, |buffer, cx| {
23910                buffer.group_until_transaction(transaction, cx);
23911            });
23912        }
23913
23914        self.unmark_text(window, cx);
23915    }
23916
23917    fn replace_and_mark_text_in_range(
23918        &mut self,
23919        range_utf16: Option<Range<usize>>,
23920        text: &str,
23921        new_selected_range_utf16: Option<Range<usize>>,
23922        window: &mut Window,
23923        cx: &mut Context<Self>,
23924    ) {
23925        if !self.input_enabled {
23926            return;
23927        }
23928
23929        let transaction = self.transact(window, cx, |this, window, cx| {
23930            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23931                let snapshot = this.buffer.read(cx).read(cx);
23932                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23933                    for marked_range in &mut marked_ranges {
23934                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23935                        marked_range.start.0 += relative_range_utf16.start;
23936                        marked_range.start =
23937                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23938                        marked_range.end =
23939                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23940                    }
23941                }
23942                Some(marked_ranges)
23943            } else if let Some(range_utf16) = range_utf16 {
23944                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23945                Some(this.selection_replacement_ranges(range_utf16, cx))
23946            } else {
23947                None
23948            };
23949
23950            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23951                let newest_selection_id = this.selections.newest_anchor().id;
23952                this.selections
23953                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23954                    .iter()
23955                    .zip(ranges_to_replace.iter())
23956                    .find_map(|(selection, range)| {
23957                        if selection.id == newest_selection_id {
23958                            Some(
23959                                (range.start.0 as isize - selection.head().0 as isize)
23960                                    ..(range.end.0 as isize - selection.head().0 as isize),
23961                            )
23962                        } else {
23963                            None
23964                        }
23965                    })
23966            });
23967
23968            cx.emit(EditorEvent::InputHandled {
23969                utf16_range_to_replace: range_to_replace,
23970                text: text.into(),
23971            });
23972
23973            if let Some(ranges) = ranges_to_replace {
23974                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23975                    s.select_ranges(ranges)
23976                });
23977            }
23978
23979            let marked_ranges = {
23980                let snapshot = this.buffer.read(cx).read(cx);
23981                this.selections
23982                    .disjoint_anchors_arc()
23983                    .iter()
23984                    .map(|selection| {
23985                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23986                    })
23987                    .collect::<Vec<_>>()
23988            };
23989
23990            if text.is_empty() {
23991                this.unmark_text(window, cx);
23992            } else {
23993                this.highlight_text::<InputComposition>(
23994                    marked_ranges.clone(),
23995                    HighlightStyle {
23996                        underline: Some(UnderlineStyle {
23997                            thickness: px(1.),
23998                            color: None,
23999                            wavy: false,
24000                        }),
24001                        ..Default::default()
24002                    },
24003                    cx,
24004                );
24005            }
24006
24007            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24008            let use_autoclose = this.use_autoclose;
24009            let use_auto_surround = this.use_auto_surround;
24010            this.set_use_autoclose(false);
24011            this.set_use_auto_surround(false);
24012            this.handle_input(text, window, cx);
24013            this.set_use_autoclose(use_autoclose);
24014            this.set_use_auto_surround(use_auto_surround);
24015
24016            if let Some(new_selected_range) = new_selected_range_utf16 {
24017                let snapshot = this.buffer.read(cx).read(cx);
24018                let new_selected_ranges = marked_ranges
24019                    .into_iter()
24020                    .map(|marked_range| {
24021                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24022                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24023                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24024                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24025                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24026                    })
24027                    .collect::<Vec<_>>();
24028
24029                drop(snapshot);
24030                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24031                    selections.select_ranges(new_selected_ranges)
24032                });
24033            }
24034        });
24035
24036        self.ime_transaction = self.ime_transaction.or(transaction);
24037        if let Some(transaction) = self.ime_transaction {
24038            self.buffer.update(cx, |buffer, cx| {
24039                buffer.group_until_transaction(transaction, cx);
24040            });
24041        }
24042
24043        if self.text_highlights::<InputComposition>(cx).is_none() {
24044            self.ime_transaction.take();
24045        }
24046    }
24047
24048    fn bounds_for_range(
24049        &mut self,
24050        range_utf16: Range<usize>,
24051        element_bounds: gpui::Bounds<Pixels>,
24052        window: &mut Window,
24053        cx: &mut Context<Self>,
24054    ) -> Option<gpui::Bounds<Pixels>> {
24055        let text_layout_details = self.text_layout_details(window);
24056        let CharacterDimensions {
24057            em_width,
24058            em_advance,
24059            line_height,
24060        } = self.character_dimensions(window);
24061
24062        let snapshot = self.snapshot(window, cx);
24063        let scroll_position = snapshot.scroll_position();
24064        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24065
24066        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24067        let x = Pixels::from(
24068            ScrollOffset::from(
24069                snapshot.x_for_display_point(start, &text_layout_details)
24070                    + self.gutter_dimensions.full_width(),
24071            ) - scroll_left,
24072        );
24073        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24074
24075        Some(Bounds {
24076            origin: element_bounds.origin + point(x, y),
24077            size: size(em_width, line_height),
24078        })
24079    }
24080
24081    fn character_index_for_point(
24082        &mut self,
24083        point: gpui::Point<Pixels>,
24084        _window: &mut Window,
24085        _cx: &mut Context<Self>,
24086    ) -> Option<usize> {
24087        let position_map = self.last_position_map.as_ref()?;
24088        if !position_map.text_hitbox.contains(&point) {
24089            return None;
24090        }
24091        let display_point = position_map.point_for_position(point).previous_valid;
24092        let anchor = position_map
24093            .snapshot
24094            .display_point_to_anchor(display_point, Bias::Left);
24095        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24096        Some(utf16_offset.0)
24097    }
24098}
24099
24100trait SelectionExt {
24101    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24102    fn spanned_rows(
24103        &self,
24104        include_end_if_at_line_start: bool,
24105        map: &DisplaySnapshot,
24106    ) -> Range<MultiBufferRow>;
24107}
24108
24109impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24110    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24111        let start = self
24112            .start
24113            .to_point(map.buffer_snapshot())
24114            .to_display_point(map);
24115        let end = self
24116            .end
24117            .to_point(map.buffer_snapshot())
24118            .to_display_point(map);
24119        if self.reversed {
24120            end..start
24121        } else {
24122            start..end
24123        }
24124    }
24125
24126    fn spanned_rows(
24127        &self,
24128        include_end_if_at_line_start: bool,
24129        map: &DisplaySnapshot,
24130    ) -> Range<MultiBufferRow> {
24131        let start = self.start.to_point(map.buffer_snapshot());
24132        let mut end = self.end.to_point(map.buffer_snapshot());
24133        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24134            end.row -= 1;
24135        }
24136
24137        let buffer_start = map.prev_line_boundary(start).0;
24138        let buffer_end = map.next_line_boundary(end).0;
24139        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24140    }
24141}
24142
24143impl<T: InvalidationRegion> InvalidationStack<T> {
24144    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24145    where
24146        S: Clone + ToOffset,
24147    {
24148        while let Some(region) = self.last() {
24149            let all_selections_inside_invalidation_ranges =
24150                if selections.len() == region.ranges().len() {
24151                    selections
24152                        .iter()
24153                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24154                        .all(|(selection, invalidation_range)| {
24155                            let head = selection.head().to_offset(buffer);
24156                            invalidation_range.start <= head && invalidation_range.end >= head
24157                        })
24158                } else {
24159                    false
24160                };
24161
24162            if all_selections_inside_invalidation_ranges {
24163                break;
24164            } else {
24165                self.pop();
24166            }
24167        }
24168    }
24169}
24170
24171impl<T> Default for InvalidationStack<T> {
24172    fn default() -> Self {
24173        Self(Default::default())
24174    }
24175}
24176
24177impl<T> Deref for InvalidationStack<T> {
24178    type Target = Vec<T>;
24179
24180    fn deref(&self) -> &Self::Target {
24181        &self.0
24182    }
24183}
24184
24185impl<T> DerefMut for InvalidationStack<T> {
24186    fn deref_mut(&mut self) -> &mut Self::Target {
24187        &mut self.0
24188    }
24189}
24190
24191impl InvalidationRegion for SnippetState {
24192    fn ranges(&self) -> &[Range<Anchor>] {
24193        &self.ranges[self.active_index]
24194    }
24195}
24196
24197fn edit_prediction_edit_text(
24198    current_snapshot: &BufferSnapshot,
24199    edits: &[(Range<Anchor>, String)],
24200    edit_preview: &EditPreview,
24201    include_deletions: bool,
24202    cx: &App,
24203) -> HighlightedText {
24204    let edits = edits
24205        .iter()
24206        .map(|(anchor, text)| {
24207            (
24208                anchor.start.text_anchor..anchor.end.text_anchor,
24209                text.clone(),
24210            )
24211        })
24212        .collect::<Vec<_>>();
24213
24214    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24215}
24216
24217fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24218    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24219    // Just show the raw edit text with basic styling
24220    let mut text = String::new();
24221    let mut highlights = Vec::new();
24222
24223    let insertion_highlight_style = HighlightStyle {
24224        color: Some(cx.theme().colors().text),
24225        ..Default::default()
24226    };
24227
24228    for (_, edit_text) in edits {
24229        let start_offset = text.len();
24230        text.push_str(edit_text);
24231        let end_offset = text.len();
24232
24233        if start_offset < end_offset {
24234            highlights.push((start_offset..end_offset, insertion_highlight_style));
24235        }
24236    }
24237
24238    HighlightedText {
24239        text: text.into(),
24240        highlights,
24241    }
24242}
24243
24244pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24245    match severity {
24246        lsp::DiagnosticSeverity::ERROR => colors.error,
24247        lsp::DiagnosticSeverity::WARNING => colors.warning,
24248        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24249        lsp::DiagnosticSeverity::HINT => colors.info,
24250        _ => colors.ignored,
24251    }
24252}
24253
24254pub fn styled_runs_for_code_label<'a>(
24255    label: &'a CodeLabel,
24256    syntax_theme: &'a theme::SyntaxTheme,
24257) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24258    let fade_out = HighlightStyle {
24259        fade_out: Some(0.35),
24260        ..Default::default()
24261    };
24262
24263    let mut prev_end = label.filter_range.end;
24264    label
24265        .runs
24266        .iter()
24267        .enumerate()
24268        .flat_map(move |(ix, (range, highlight_id))| {
24269            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24270                style
24271            } else {
24272                return Default::default();
24273            };
24274            let muted_style = style.highlight(fade_out);
24275
24276            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24277            if range.start >= label.filter_range.end {
24278                if range.start > prev_end {
24279                    runs.push((prev_end..range.start, fade_out));
24280                }
24281                runs.push((range.clone(), muted_style));
24282            } else if range.end <= label.filter_range.end {
24283                runs.push((range.clone(), style));
24284            } else {
24285                runs.push((range.start..label.filter_range.end, style));
24286                runs.push((label.filter_range.end..range.end, muted_style));
24287            }
24288            prev_end = cmp::max(prev_end, range.end);
24289
24290            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24291                runs.push((prev_end..label.text.len(), fade_out));
24292            }
24293
24294            runs
24295        })
24296}
24297
24298pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24299    let mut prev_index = 0;
24300    let mut prev_codepoint: Option<char> = None;
24301    text.char_indices()
24302        .chain([(text.len(), '\0')])
24303        .filter_map(move |(index, codepoint)| {
24304            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24305            let is_boundary = index == text.len()
24306                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24307                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24308            if is_boundary {
24309                let chunk = &text[prev_index..index];
24310                prev_index = index;
24311                Some(chunk)
24312            } else {
24313                None
24314            }
24315        })
24316}
24317
24318pub trait RangeToAnchorExt: Sized {
24319    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24320
24321    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24322        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24323        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24324    }
24325}
24326
24327impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24328    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24329        let start_offset = self.start.to_offset(snapshot);
24330        let end_offset = self.end.to_offset(snapshot);
24331        if start_offset == end_offset {
24332            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24333        } else {
24334            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24335        }
24336    }
24337}
24338
24339pub trait RowExt {
24340    fn as_f64(&self) -> f64;
24341
24342    fn next_row(&self) -> Self;
24343
24344    fn previous_row(&self) -> Self;
24345
24346    fn minus(&self, other: Self) -> u32;
24347}
24348
24349impl RowExt for DisplayRow {
24350    fn as_f64(&self) -> f64 {
24351        self.0 as _
24352    }
24353
24354    fn next_row(&self) -> Self {
24355        Self(self.0 + 1)
24356    }
24357
24358    fn previous_row(&self) -> Self {
24359        Self(self.0.saturating_sub(1))
24360    }
24361
24362    fn minus(&self, other: Self) -> u32 {
24363        self.0 - other.0
24364    }
24365}
24366
24367impl RowExt for MultiBufferRow {
24368    fn as_f64(&self) -> f64 {
24369        self.0 as _
24370    }
24371
24372    fn next_row(&self) -> Self {
24373        Self(self.0 + 1)
24374    }
24375
24376    fn previous_row(&self) -> Self {
24377        Self(self.0.saturating_sub(1))
24378    }
24379
24380    fn minus(&self, other: Self) -> u32 {
24381        self.0 - other.0
24382    }
24383}
24384
24385trait RowRangeExt {
24386    type Row;
24387
24388    fn len(&self) -> usize;
24389
24390    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24391}
24392
24393impl RowRangeExt for Range<MultiBufferRow> {
24394    type Row = MultiBufferRow;
24395
24396    fn len(&self) -> usize {
24397        (self.end.0 - self.start.0) as usize
24398    }
24399
24400    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24401        (self.start.0..self.end.0).map(MultiBufferRow)
24402    }
24403}
24404
24405impl RowRangeExt for Range<DisplayRow> {
24406    type Row = DisplayRow;
24407
24408    fn len(&self) -> usize {
24409        (self.end.0 - self.start.0) as usize
24410    }
24411
24412    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24413        (self.start.0..self.end.0).map(DisplayRow)
24414    }
24415}
24416
24417/// If select range has more than one line, we
24418/// just point the cursor to range.start.
24419fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24420    if range.start.row == range.end.row {
24421        range
24422    } else {
24423        range.start..range.start
24424    }
24425}
24426pub struct KillRing(ClipboardItem);
24427impl Global for KillRing {}
24428
24429const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24430
24431enum BreakpointPromptEditAction {
24432    Log,
24433    Condition,
24434    HitCondition,
24435}
24436
24437struct BreakpointPromptEditor {
24438    pub(crate) prompt: Entity<Editor>,
24439    editor: WeakEntity<Editor>,
24440    breakpoint_anchor: Anchor,
24441    breakpoint: Breakpoint,
24442    edit_action: BreakpointPromptEditAction,
24443    block_ids: HashSet<CustomBlockId>,
24444    editor_margins: Arc<Mutex<EditorMargins>>,
24445    _subscriptions: Vec<Subscription>,
24446}
24447
24448impl BreakpointPromptEditor {
24449    const MAX_LINES: u8 = 4;
24450
24451    fn new(
24452        editor: WeakEntity<Editor>,
24453        breakpoint_anchor: Anchor,
24454        breakpoint: Breakpoint,
24455        edit_action: BreakpointPromptEditAction,
24456        window: &mut Window,
24457        cx: &mut Context<Self>,
24458    ) -> Self {
24459        let base_text = match edit_action {
24460            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24461            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24462            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24463        }
24464        .map(|msg| msg.to_string())
24465        .unwrap_or_default();
24466
24467        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24468        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24469
24470        let prompt = cx.new(|cx| {
24471            let mut prompt = Editor::new(
24472                EditorMode::AutoHeight {
24473                    min_lines: 1,
24474                    max_lines: Some(Self::MAX_LINES as usize),
24475                },
24476                buffer,
24477                None,
24478                window,
24479                cx,
24480            );
24481            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24482            prompt.set_show_cursor_when_unfocused(false, cx);
24483            prompt.set_placeholder_text(
24484                match edit_action {
24485                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24486                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24487                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24488                },
24489                window,
24490                cx,
24491            );
24492
24493            prompt
24494        });
24495
24496        Self {
24497            prompt,
24498            editor,
24499            breakpoint_anchor,
24500            breakpoint,
24501            edit_action,
24502            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24503            block_ids: Default::default(),
24504            _subscriptions: vec![],
24505        }
24506    }
24507
24508    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24509        self.block_ids.extend(block_ids)
24510    }
24511
24512    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24513        if let Some(editor) = self.editor.upgrade() {
24514            let message = self
24515                .prompt
24516                .read(cx)
24517                .buffer
24518                .read(cx)
24519                .as_singleton()
24520                .expect("A multi buffer in breakpoint prompt isn't possible")
24521                .read(cx)
24522                .as_rope()
24523                .to_string();
24524
24525            editor.update(cx, |editor, cx| {
24526                editor.edit_breakpoint_at_anchor(
24527                    self.breakpoint_anchor,
24528                    self.breakpoint.clone(),
24529                    match self.edit_action {
24530                        BreakpointPromptEditAction::Log => {
24531                            BreakpointEditAction::EditLogMessage(message.into())
24532                        }
24533                        BreakpointPromptEditAction::Condition => {
24534                            BreakpointEditAction::EditCondition(message.into())
24535                        }
24536                        BreakpointPromptEditAction::HitCondition => {
24537                            BreakpointEditAction::EditHitCondition(message.into())
24538                        }
24539                    },
24540                    cx,
24541                );
24542
24543                editor.remove_blocks(self.block_ids.clone(), None, cx);
24544                cx.focus_self(window);
24545            });
24546        }
24547    }
24548
24549    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24550        self.editor
24551            .update(cx, |editor, cx| {
24552                editor.remove_blocks(self.block_ids.clone(), None, cx);
24553                window.focus(&editor.focus_handle);
24554            })
24555            .log_err();
24556    }
24557
24558    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24559        let settings = ThemeSettings::get_global(cx);
24560        let text_style = TextStyle {
24561            color: if self.prompt.read(cx).read_only(cx) {
24562                cx.theme().colors().text_disabled
24563            } else {
24564                cx.theme().colors().text
24565            },
24566            font_family: settings.buffer_font.family.clone(),
24567            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24568            font_size: settings.buffer_font_size(cx).into(),
24569            font_weight: settings.buffer_font.weight,
24570            line_height: relative(settings.buffer_line_height.value()),
24571            ..Default::default()
24572        };
24573        EditorElement::new(
24574            &self.prompt,
24575            EditorStyle {
24576                background: cx.theme().colors().editor_background,
24577                local_player: cx.theme().players().local(),
24578                text: text_style,
24579                ..Default::default()
24580            },
24581        )
24582    }
24583}
24584
24585impl Render for BreakpointPromptEditor {
24586    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24587        let editor_margins = *self.editor_margins.lock();
24588        let gutter_dimensions = editor_margins.gutter;
24589        h_flex()
24590            .key_context("Editor")
24591            .bg(cx.theme().colors().editor_background)
24592            .border_y_1()
24593            .border_color(cx.theme().status().info_border)
24594            .size_full()
24595            .py(window.line_height() / 2.5)
24596            .on_action(cx.listener(Self::confirm))
24597            .on_action(cx.listener(Self::cancel))
24598            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24599            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24600    }
24601}
24602
24603impl Focusable for BreakpointPromptEditor {
24604    fn focus_handle(&self, cx: &App) -> FocusHandle {
24605        self.prompt.focus_handle(cx)
24606    }
24607}
24608
24609fn all_edits_insertions_or_deletions(
24610    edits: &Vec<(Range<Anchor>, String)>,
24611    snapshot: &MultiBufferSnapshot,
24612) -> bool {
24613    let mut all_insertions = true;
24614    let mut all_deletions = true;
24615
24616    for (range, new_text) in edits.iter() {
24617        let range_is_empty = range.to_offset(snapshot).is_empty();
24618        let text_is_empty = new_text.is_empty();
24619
24620        if range_is_empty != text_is_empty {
24621            if range_is_empty {
24622                all_deletions = false;
24623            } else {
24624                all_insertions = false;
24625            }
24626        } else {
24627            return false;
24628        }
24629
24630        if !all_insertions && !all_deletions {
24631            return false;
24632        }
24633    }
24634    all_insertions || all_deletions
24635}
24636
24637struct MissingEditPredictionKeybindingTooltip;
24638
24639impl Render for MissingEditPredictionKeybindingTooltip {
24640    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24641        ui::tooltip_container(cx, |container, cx| {
24642            container
24643                .flex_shrink_0()
24644                .max_w_80()
24645                .min_h(rems_from_px(124.))
24646                .justify_between()
24647                .child(
24648                    v_flex()
24649                        .flex_1()
24650                        .text_ui_sm(cx)
24651                        .child(Label::new("Conflict with Accept Keybinding"))
24652                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24653                )
24654                .child(
24655                    h_flex()
24656                        .pb_1()
24657                        .gap_1()
24658                        .items_end()
24659                        .w_full()
24660                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24661                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24662                        }))
24663                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24664                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24665                        })),
24666                )
24667        })
24668    }
24669}
24670
24671#[derive(Debug, Clone, Copy, PartialEq)]
24672pub struct LineHighlight {
24673    pub background: Background,
24674    pub border: Option<gpui::Hsla>,
24675    pub include_gutter: bool,
24676    pub type_id: Option<TypeId>,
24677}
24678
24679struct LineManipulationResult {
24680    pub new_text: String,
24681    pub line_count_before: usize,
24682    pub line_count_after: usize,
24683}
24684
24685fn render_diff_hunk_controls(
24686    row: u32,
24687    status: &DiffHunkStatus,
24688    hunk_range: Range<Anchor>,
24689    is_created_file: bool,
24690    line_height: Pixels,
24691    editor: &Entity<Editor>,
24692    _window: &mut Window,
24693    cx: &mut App,
24694) -> AnyElement {
24695    h_flex()
24696        .h(line_height)
24697        .mr_1()
24698        .gap_1()
24699        .px_0p5()
24700        .pb_1()
24701        .border_x_1()
24702        .border_b_1()
24703        .border_color(cx.theme().colors().border_variant)
24704        .rounded_b_lg()
24705        .bg(cx.theme().colors().editor_background)
24706        .gap_1()
24707        .block_mouse_except_scroll()
24708        .shadow_md()
24709        .child(if status.has_secondary_hunk() {
24710            Button::new(("stage", row as u64), "Stage")
24711                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24712                .tooltip({
24713                    let focus_handle = editor.focus_handle(cx);
24714                    move |_window, cx| {
24715                        Tooltip::for_action_in(
24716                            "Stage Hunk",
24717                            &::git::ToggleStaged,
24718                            &focus_handle,
24719                            cx,
24720                        )
24721                    }
24722                })
24723                .on_click({
24724                    let editor = editor.clone();
24725                    move |_event, _window, cx| {
24726                        editor.update(cx, |editor, cx| {
24727                            editor.stage_or_unstage_diff_hunks(
24728                                true,
24729                                vec![hunk_range.start..hunk_range.start],
24730                                cx,
24731                            );
24732                        });
24733                    }
24734                })
24735        } else {
24736            Button::new(("unstage", row as u64), "Unstage")
24737                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24738                .tooltip({
24739                    let focus_handle = editor.focus_handle(cx);
24740                    move |_window, cx| {
24741                        Tooltip::for_action_in(
24742                            "Unstage Hunk",
24743                            &::git::ToggleStaged,
24744                            &focus_handle,
24745                            cx,
24746                        )
24747                    }
24748                })
24749                .on_click({
24750                    let editor = editor.clone();
24751                    move |_event, _window, cx| {
24752                        editor.update(cx, |editor, cx| {
24753                            editor.stage_or_unstage_diff_hunks(
24754                                false,
24755                                vec![hunk_range.start..hunk_range.start],
24756                                cx,
24757                            );
24758                        });
24759                    }
24760                })
24761        })
24762        .child(
24763            Button::new(("restore", row as u64), "Restore")
24764                .tooltip({
24765                    let focus_handle = editor.focus_handle(cx);
24766                    move |_window, cx| {
24767                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24768                    }
24769                })
24770                .on_click({
24771                    let editor = editor.clone();
24772                    move |_event, window, cx| {
24773                        editor.update(cx, |editor, cx| {
24774                            let snapshot = editor.snapshot(window, cx);
24775                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24776                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24777                        });
24778                    }
24779                })
24780                .disabled(is_created_file),
24781        )
24782        .when(
24783            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24784            |el| {
24785                el.child(
24786                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24787                        .shape(IconButtonShape::Square)
24788                        .icon_size(IconSize::Small)
24789                        // .disabled(!has_multiple_hunks)
24790                        .tooltip({
24791                            let focus_handle = editor.focus_handle(cx);
24792                            move |_window, cx| {
24793                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24794                            }
24795                        })
24796                        .on_click({
24797                            let editor = editor.clone();
24798                            move |_event, window, cx| {
24799                                editor.update(cx, |editor, cx| {
24800                                    let snapshot = editor.snapshot(window, cx);
24801                                    let position =
24802                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24803                                    editor.go_to_hunk_before_or_after_position(
24804                                        &snapshot,
24805                                        position,
24806                                        Direction::Next,
24807                                        window,
24808                                        cx,
24809                                    );
24810                                    editor.expand_selected_diff_hunks(cx);
24811                                });
24812                            }
24813                        }),
24814                )
24815                .child(
24816                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24817                        .shape(IconButtonShape::Square)
24818                        .icon_size(IconSize::Small)
24819                        // .disabled(!has_multiple_hunks)
24820                        .tooltip({
24821                            let focus_handle = editor.focus_handle(cx);
24822                            move |_window, cx| {
24823                                Tooltip::for_action_in(
24824                                    "Previous Hunk",
24825                                    &GoToPreviousHunk,
24826                                    &focus_handle,
24827                                    cx,
24828                                )
24829                            }
24830                        })
24831                        .on_click({
24832                            let editor = editor.clone();
24833                            move |_event, window, cx| {
24834                                editor.update(cx, |editor, cx| {
24835                                    let snapshot = editor.snapshot(window, cx);
24836                                    let point =
24837                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24838                                    editor.go_to_hunk_before_or_after_position(
24839                                        &snapshot,
24840                                        point,
24841                                        Direction::Prev,
24842                                        window,
24843                                        cx,
24844                                    );
24845                                    editor.expand_selected_diff_hunks(cx);
24846                                });
24847                            }
24848                        }),
24849                )
24850            },
24851        )
24852        .into_any_element()
24853}
24854
24855pub fn multibuffer_context_lines(cx: &App) -> u32 {
24856    EditorSettings::try_get(cx)
24857        .map(|settings| settings.excerpt_context_lines)
24858        .unwrap_or(2)
24859        .min(32)
24860}