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    autoindent_mode: Option<AutoindentMode>,
 1073    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1074    input_enabled: bool,
 1075    use_modal_editing: bool,
 1076    read_only: bool,
 1077    leader_id: Option<CollaboratorId>,
 1078    remote_id: Option<ViewId>,
 1079    pub hover_state: HoverState,
 1080    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1081    gutter_hovered: bool,
 1082    hovered_link_state: Option<HoveredLinkState>,
 1083    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1084    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1085    active_edit_prediction: Option<EditPredictionState>,
 1086    /// Used to prevent flickering as the user types while the menu is open
 1087    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1088    edit_prediction_settings: EditPredictionSettings,
 1089    edit_predictions_hidden_for_vim_mode: bool,
 1090    show_edit_predictions_override: Option<bool>,
 1091    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1092    edit_prediction_preview: EditPredictionPreview,
 1093    edit_prediction_indent_conflict: bool,
 1094    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1095    next_inlay_id: usize,
 1096    next_color_inlay_id: usize,
 1097    _subscriptions: Vec<Subscription>,
 1098    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1099    gutter_dimensions: GutterDimensions,
 1100    style: Option<EditorStyle>,
 1101    text_style_refinement: Option<TextStyleRefinement>,
 1102    next_editor_action_id: EditorActionId,
 1103    editor_actions: Rc<
 1104        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1105    >,
 1106    use_autoclose: bool,
 1107    use_auto_surround: bool,
 1108    auto_replace_emoji_shortcode: bool,
 1109    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1110    show_git_blame_gutter: bool,
 1111    show_git_blame_inline: bool,
 1112    show_git_blame_inline_delay_task: Option<Task<()>>,
 1113    git_blame_inline_enabled: bool,
 1114    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1115    serialize_dirty_buffers: bool,
 1116    show_selection_menu: Option<bool>,
 1117    blame: Option<Entity<GitBlame>>,
 1118    blame_subscription: Option<Subscription>,
 1119    custom_context_menu: Option<
 1120        Box<
 1121            dyn 'static
 1122                + Fn(
 1123                    &mut Self,
 1124                    DisplayPoint,
 1125                    &mut Window,
 1126                    &mut Context<Self>,
 1127                ) -> Option<Entity<ui::ContextMenu>>,
 1128        >,
 1129    >,
 1130    last_bounds: Option<Bounds<Pixels>>,
 1131    last_position_map: Option<Rc<PositionMap>>,
 1132    expect_bounds_change: Option<Bounds<Pixels>>,
 1133    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1134    tasks_update_task: Option<Task<()>>,
 1135    breakpoint_store: Option<Entity<BreakpointStore>>,
 1136    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1137    hovered_diff_hunk_row: Option<DisplayRow>,
 1138    pull_diagnostics_task: Task<()>,
 1139    in_project_search: bool,
 1140    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1141    breadcrumb_header: Option<String>,
 1142    focused_block: Option<FocusedBlock>,
 1143    next_scroll_position: NextScrollCursorCenterTopBottom,
 1144    addons: HashMap<TypeId, Box<dyn Addon>>,
 1145    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1146    load_diff_task: Option<Shared<Task<()>>>,
 1147    /// Whether we are temporarily displaying a diff other than git's
 1148    temporary_diff_override: bool,
 1149    selection_mark_mode: bool,
 1150    toggle_fold_multiple_buffers: Task<()>,
 1151    _scroll_cursor_center_top_bottom_task: Task<()>,
 1152    serialize_selections: Task<()>,
 1153    serialize_folds: Task<()>,
 1154    mouse_cursor_hidden: bool,
 1155    minimap: Option<Entity<Self>>,
 1156    hide_mouse_mode: HideMouseMode,
 1157    pub change_list: ChangeList,
 1158    inline_value_cache: InlineValueCache,
 1159    selection_drag_state: SelectionDragState,
 1160    colors: Option<LspColorData>,
 1161    post_scroll_update: Task<()>,
 1162    refresh_colors_task: Task<()>,
 1163    inlay_hints: Option<LspInlayHintData>,
 1164    folding_newlines: Task<()>,
 1165    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1166}
 1167
 1168fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1169    if debounce_ms > 0 {
 1170        Some(Duration::from_millis(debounce_ms))
 1171    } else {
 1172        None
 1173    }
 1174}
 1175
 1176#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1177enum NextScrollCursorCenterTopBottom {
 1178    #[default]
 1179    Center,
 1180    Top,
 1181    Bottom,
 1182}
 1183
 1184impl NextScrollCursorCenterTopBottom {
 1185    fn next(&self) -> Self {
 1186        match self {
 1187            Self::Center => Self::Top,
 1188            Self::Top => Self::Bottom,
 1189            Self::Bottom => Self::Center,
 1190        }
 1191    }
 1192}
 1193
 1194#[derive(Clone)]
 1195pub struct EditorSnapshot {
 1196    pub mode: EditorMode,
 1197    show_gutter: bool,
 1198    show_line_numbers: Option<bool>,
 1199    show_git_diff_gutter: Option<bool>,
 1200    show_code_actions: Option<bool>,
 1201    show_runnables: Option<bool>,
 1202    show_breakpoints: Option<bool>,
 1203    git_blame_gutter_max_author_length: Option<usize>,
 1204    pub display_snapshot: DisplaySnapshot,
 1205    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1206    is_focused: bool,
 1207    scroll_anchor: ScrollAnchor,
 1208    ongoing_scroll: OngoingScroll,
 1209    current_line_highlight: CurrentLineHighlight,
 1210    gutter_hovered: bool,
 1211}
 1212
 1213#[derive(Default, Debug, Clone, Copy)]
 1214pub struct GutterDimensions {
 1215    pub left_padding: Pixels,
 1216    pub right_padding: Pixels,
 1217    pub width: Pixels,
 1218    pub margin: Pixels,
 1219    pub git_blame_entries_width: Option<Pixels>,
 1220}
 1221
 1222impl GutterDimensions {
 1223    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1224        Self {
 1225            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1226            ..Default::default()
 1227        }
 1228    }
 1229
 1230    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1231        -cx.text_system().descent(font_id, font_size)
 1232    }
 1233    /// The full width of the space taken up by the gutter.
 1234    pub fn full_width(&self) -> Pixels {
 1235        self.margin + self.width
 1236    }
 1237
 1238    /// The width of the space reserved for the fold indicators,
 1239    /// use alongside 'justify_end' and `gutter_width` to
 1240    /// right align content with the line numbers
 1241    pub fn fold_area_width(&self) -> Pixels {
 1242        self.margin + self.right_padding
 1243    }
 1244}
 1245
 1246struct CharacterDimensions {
 1247    em_width: Pixels,
 1248    em_advance: Pixels,
 1249    line_height: Pixels,
 1250}
 1251
 1252#[derive(Debug)]
 1253pub struct RemoteSelection {
 1254    pub replica_id: ReplicaId,
 1255    pub selection: Selection<Anchor>,
 1256    pub cursor_shape: CursorShape,
 1257    pub collaborator_id: CollaboratorId,
 1258    pub line_mode: bool,
 1259    pub user_name: Option<SharedString>,
 1260    pub color: PlayerColor,
 1261}
 1262
 1263#[derive(Clone, Debug)]
 1264struct SelectionHistoryEntry {
 1265    selections: Arc<[Selection<Anchor>]>,
 1266    select_next_state: Option<SelectNextState>,
 1267    select_prev_state: Option<SelectNextState>,
 1268    add_selections_state: Option<AddSelectionsState>,
 1269}
 1270
 1271#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1272enum SelectionHistoryMode {
 1273    Normal,
 1274    Undoing,
 1275    Redoing,
 1276    Skipping,
 1277}
 1278
 1279#[derive(Clone, PartialEq, Eq, Hash)]
 1280struct HoveredCursor {
 1281    replica_id: ReplicaId,
 1282    selection_id: usize,
 1283}
 1284
 1285impl Default for SelectionHistoryMode {
 1286    fn default() -> Self {
 1287        Self::Normal
 1288    }
 1289}
 1290
 1291#[derive(Debug)]
 1292/// SelectionEffects controls the side-effects of updating the selection.
 1293///
 1294/// The default behaviour does "what you mostly want":
 1295/// - it pushes to the nav history if the cursor moved by >10 lines
 1296/// - it re-triggers completion requests
 1297/// - it scrolls to fit
 1298///
 1299/// You might want to modify these behaviours. For example when doing a "jump"
 1300/// like go to definition, we always want to add to nav history; but when scrolling
 1301/// in vim mode we never do.
 1302///
 1303/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1304/// move.
 1305#[derive(Clone)]
 1306pub struct SelectionEffects {
 1307    nav_history: Option<bool>,
 1308    completions: bool,
 1309    scroll: Option<Autoscroll>,
 1310}
 1311
 1312impl Default for SelectionEffects {
 1313    fn default() -> Self {
 1314        Self {
 1315            nav_history: None,
 1316            completions: true,
 1317            scroll: Some(Autoscroll::fit()),
 1318        }
 1319    }
 1320}
 1321impl SelectionEffects {
 1322    pub fn scroll(scroll: Autoscroll) -> Self {
 1323        Self {
 1324            scroll: Some(scroll),
 1325            ..Default::default()
 1326        }
 1327    }
 1328
 1329    pub fn no_scroll() -> Self {
 1330        Self {
 1331            scroll: None,
 1332            ..Default::default()
 1333        }
 1334    }
 1335
 1336    pub fn completions(self, completions: bool) -> Self {
 1337        Self {
 1338            completions,
 1339            ..self
 1340        }
 1341    }
 1342
 1343    pub fn nav_history(self, nav_history: bool) -> Self {
 1344        Self {
 1345            nav_history: Some(nav_history),
 1346            ..self
 1347        }
 1348    }
 1349}
 1350
 1351struct DeferredSelectionEffectsState {
 1352    changed: bool,
 1353    effects: SelectionEffects,
 1354    old_cursor_position: Anchor,
 1355    history_entry: SelectionHistoryEntry,
 1356}
 1357
 1358#[derive(Default)]
 1359struct SelectionHistory {
 1360    #[allow(clippy::type_complexity)]
 1361    selections_by_transaction:
 1362        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1363    mode: SelectionHistoryMode,
 1364    undo_stack: VecDeque<SelectionHistoryEntry>,
 1365    redo_stack: VecDeque<SelectionHistoryEntry>,
 1366}
 1367
 1368impl SelectionHistory {
 1369    #[track_caller]
 1370    fn insert_transaction(
 1371        &mut self,
 1372        transaction_id: TransactionId,
 1373        selections: Arc<[Selection<Anchor>]>,
 1374    ) {
 1375        if selections.is_empty() {
 1376            log::error!(
 1377                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1378                std::panic::Location::caller()
 1379            );
 1380            return;
 1381        }
 1382        self.selections_by_transaction
 1383            .insert(transaction_id, (selections, None));
 1384    }
 1385
 1386    #[allow(clippy::type_complexity)]
 1387    fn transaction(
 1388        &self,
 1389        transaction_id: TransactionId,
 1390    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1391        self.selections_by_transaction.get(&transaction_id)
 1392    }
 1393
 1394    #[allow(clippy::type_complexity)]
 1395    fn transaction_mut(
 1396        &mut self,
 1397        transaction_id: TransactionId,
 1398    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1399        self.selections_by_transaction.get_mut(&transaction_id)
 1400    }
 1401
 1402    fn push(&mut self, entry: SelectionHistoryEntry) {
 1403        if !entry.selections.is_empty() {
 1404            match self.mode {
 1405                SelectionHistoryMode::Normal => {
 1406                    self.push_undo(entry);
 1407                    self.redo_stack.clear();
 1408                }
 1409                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1410                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1411                SelectionHistoryMode::Skipping => {}
 1412            }
 1413        }
 1414    }
 1415
 1416    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1417        if self
 1418            .undo_stack
 1419            .back()
 1420            .is_none_or(|e| e.selections != entry.selections)
 1421        {
 1422            self.undo_stack.push_back(entry);
 1423            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1424                self.undo_stack.pop_front();
 1425            }
 1426        }
 1427    }
 1428
 1429    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1430        if self
 1431            .redo_stack
 1432            .back()
 1433            .is_none_or(|e| e.selections != entry.selections)
 1434        {
 1435            self.redo_stack.push_back(entry);
 1436            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1437                self.redo_stack.pop_front();
 1438            }
 1439        }
 1440    }
 1441}
 1442
 1443#[derive(Clone, Copy)]
 1444pub struct RowHighlightOptions {
 1445    pub autoscroll: bool,
 1446    pub include_gutter: bool,
 1447}
 1448
 1449impl Default for RowHighlightOptions {
 1450    fn default() -> Self {
 1451        Self {
 1452            autoscroll: Default::default(),
 1453            include_gutter: true,
 1454        }
 1455    }
 1456}
 1457
 1458struct RowHighlight {
 1459    index: usize,
 1460    range: Range<Anchor>,
 1461    color: Hsla,
 1462    options: RowHighlightOptions,
 1463    type_id: TypeId,
 1464}
 1465
 1466#[derive(Clone, Debug)]
 1467struct AddSelectionsState {
 1468    groups: Vec<AddSelectionsGroup>,
 1469}
 1470
 1471#[derive(Clone, Debug)]
 1472struct AddSelectionsGroup {
 1473    above: bool,
 1474    stack: Vec<usize>,
 1475}
 1476
 1477#[derive(Clone)]
 1478struct SelectNextState {
 1479    query: AhoCorasick,
 1480    wordwise: bool,
 1481    done: bool,
 1482}
 1483
 1484impl std::fmt::Debug for SelectNextState {
 1485    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1486        f.debug_struct(std::any::type_name::<Self>())
 1487            .field("wordwise", &self.wordwise)
 1488            .field("done", &self.done)
 1489            .finish()
 1490    }
 1491}
 1492
 1493#[derive(Debug)]
 1494struct AutocloseRegion {
 1495    selection_id: usize,
 1496    range: Range<Anchor>,
 1497    pair: BracketPair,
 1498}
 1499
 1500#[derive(Debug)]
 1501struct SnippetState {
 1502    ranges: Vec<Vec<Range<Anchor>>>,
 1503    active_index: usize,
 1504    choices: Vec<Option<Vec<String>>>,
 1505}
 1506
 1507#[doc(hidden)]
 1508pub struct RenameState {
 1509    pub range: Range<Anchor>,
 1510    pub old_name: Arc<str>,
 1511    pub editor: Entity<Editor>,
 1512    block_id: CustomBlockId,
 1513}
 1514
 1515struct InvalidationStack<T>(Vec<T>);
 1516
 1517struct RegisteredEditPredictionProvider {
 1518    provider: Arc<dyn EditPredictionProviderHandle>,
 1519    _subscription: Subscription,
 1520}
 1521
 1522#[derive(Debug, PartialEq, Eq)]
 1523pub struct ActiveDiagnosticGroup {
 1524    pub active_range: Range<Anchor>,
 1525    pub active_message: String,
 1526    pub group_id: usize,
 1527    pub blocks: HashSet<CustomBlockId>,
 1528}
 1529
 1530#[derive(Debug, PartialEq, Eq)]
 1531
 1532pub(crate) enum ActiveDiagnostic {
 1533    None,
 1534    All,
 1535    Group(ActiveDiagnosticGroup),
 1536}
 1537
 1538#[derive(Serialize, Deserialize, Clone, Debug)]
 1539pub struct ClipboardSelection {
 1540    /// The number of bytes in this selection.
 1541    pub len: usize,
 1542    /// Whether this was a full-line selection.
 1543    pub is_entire_line: bool,
 1544    /// The indentation of the first line when this content was originally copied.
 1545    pub first_line_indent: u32,
 1546}
 1547
 1548// selections, scroll behavior, was newest selection reversed
 1549type SelectSyntaxNodeHistoryState = (
 1550    Box<[Selection<usize>]>,
 1551    SelectSyntaxNodeScrollBehavior,
 1552    bool,
 1553);
 1554
 1555#[derive(Default)]
 1556struct SelectSyntaxNodeHistory {
 1557    stack: Vec<SelectSyntaxNodeHistoryState>,
 1558    // disable temporarily to allow changing selections without losing the stack
 1559    pub disable_clearing: bool,
 1560}
 1561
 1562impl SelectSyntaxNodeHistory {
 1563    pub fn try_clear(&mut self) {
 1564        if !self.disable_clearing {
 1565            self.stack.clear();
 1566        }
 1567    }
 1568
 1569    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1570        self.stack.push(selection);
 1571    }
 1572
 1573    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1574        self.stack.pop()
 1575    }
 1576}
 1577
 1578enum SelectSyntaxNodeScrollBehavior {
 1579    CursorTop,
 1580    FitSelection,
 1581    CursorBottom,
 1582}
 1583
 1584#[derive(Debug)]
 1585pub(crate) struct NavigationData {
 1586    cursor_anchor: Anchor,
 1587    cursor_position: Point,
 1588    scroll_anchor: ScrollAnchor,
 1589    scroll_top_row: u32,
 1590}
 1591
 1592#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1593pub enum GotoDefinitionKind {
 1594    Symbol,
 1595    Declaration,
 1596    Type,
 1597    Implementation,
 1598}
 1599
 1600pub enum FormatTarget {
 1601    Buffers(HashSet<Entity<Buffer>>),
 1602    Ranges(Vec<Range<MultiBufferPoint>>),
 1603}
 1604
 1605pub(crate) struct FocusedBlock {
 1606    id: BlockId,
 1607    focus_handle: WeakFocusHandle,
 1608}
 1609
 1610#[derive(Clone)]
 1611enum JumpData {
 1612    MultiBufferRow {
 1613        row: MultiBufferRow,
 1614        line_offset_from_top: u32,
 1615    },
 1616    MultiBufferPoint {
 1617        excerpt_id: ExcerptId,
 1618        position: Point,
 1619        anchor: text::Anchor,
 1620        line_offset_from_top: u32,
 1621    },
 1622}
 1623
 1624pub enum MultibufferSelectionMode {
 1625    First,
 1626    All,
 1627}
 1628
 1629#[derive(Clone, Copy, Debug, Default)]
 1630pub struct RewrapOptions {
 1631    pub override_language_settings: bool,
 1632    pub preserve_existing_whitespace: bool,
 1633}
 1634
 1635impl Editor {
 1636    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1637        let buffer = cx.new(|cx| Buffer::local("", cx));
 1638        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1639        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1640    }
 1641
 1642    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1643        let buffer = cx.new(|cx| Buffer::local("", cx));
 1644        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1645        Self::new(EditorMode::full(), buffer, None, window, cx)
 1646    }
 1647
 1648    pub fn auto_height(
 1649        min_lines: usize,
 1650        max_lines: usize,
 1651        window: &mut Window,
 1652        cx: &mut Context<Self>,
 1653    ) -> Self {
 1654        let buffer = cx.new(|cx| Buffer::local("", cx));
 1655        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1656        Self::new(
 1657            EditorMode::AutoHeight {
 1658                min_lines,
 1659                max_lines: Some(max_lines),
 1660            },
 1661            buffer,
 1662            None,
 1663            window,
 1664            cx,
 1665        )
 1666    }
 1667
 1668    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1669    /// The editor grows as tall as needed to fit its content.
 1670    pub fn auto_height_unbounded(
 1671        min_lines: usize,
 1672        window: &mut Window,
 1673        cx: &mut Context<Self>,
 1674    ) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(
 1678            EditorMode::AutoHeight {
 1679                min_lines,
 1680                max_lines: None,
 1681            },
 1682            buffer,
 1683            None,
 1684            window,
 1685            cx,
 1686        )
 1687    }
 1688
 1689    pub fn for_buffer(
 1690        buffer: Entity<Buffer>,
 1691        project: Option<Entity<Project>>,
 1692        window: &mut Window,
 1693        cx: &mut Context<Self>,
 1694    ) -> Self {
 1695        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1696        Self::new(EditorMode::full(), buffer, project, window, cx)
 1697    }
 1698
 1699    pub fn for_multibuffer(
 1700        buffer: Entity<MultiBuffer>,
 1701        project: Option<Entity<Project>>,
 1702        window: &mut Window,
 1703        cx: &mut Context<Self>,
 1704    ) -> Self {
 1705        Self::new(EditorMode::full(), buffer, project, window, cx)
 1706    }
 1707
 1708    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1709        let mut clone = Self::new(
 1710            self.mode.clone(),
 1711            self.buffer.clone(),
 1712            self.project.clone(),
 1713            window,
 1714            cx,
 1715        );
 1716        self.display_map.update(cx, |display_map, cx| {
 1717            let snapshot = display_map.snapshot(cx);
 1718            clone.display_map.update(cx, |display_map, cx| {
 1719                display_map.set_state(&snapshot, cx);
 1720            });
 1721        });
 1722        clone.folds_did_change(cx);
 1723        clone.selections.clone_state(&self.selections);
 1724        clone.scroll_manager.clone_state(&self.scroll_manager);
 1725        clone.searchable = self.searchable;
 1726        clone.read_only = self.read_only;
 1727        clone
 1728    }
 1729
 1730    pub fn new(
 1731        mode: EditorMode,
 1732        buffer: Entity<MultiBuffer>,
 1733        project: Option<Entity<Project>>,
 1734        window: &mut Window,
 1735        cx: &mut Context<Self>,
 1736    ) -> Self {
 1737        Editor::new_internal(mode, buffer, project, None, window, cx)
 1738    }
 1739
 1740    fn new_internal(
 1741        mode: EditorMode,
 1742        multi_buffer: Entity<MultiBuffer>,
 1743        project: Option<Entity<Project>>,
 1744        display_map: Option<Entity<DisplayMap>>,
 1745        window: &mut Window,
 1746        cx: &mut Context<Self>,
 1747    ) -> Self {
 1748        debug_assert!(
 1749            display_map.is_none() || mode.is_minimap(),
 1750            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1751        );
 1752
 1753        let full_mode = mode.is_full();
 1754        let is_minimap = mode.is_minimap();
 1755        let diagnostics_max_severity = if full_mode {
 1756            EditorSettings::get_global(cx)
 1757                .diagnostics_max_severity
 1758                .unwrap_or(DiagnosticSeverity::Hint)
 1759        } else {
 1760            DiagnosticSeverity::Off
 1761        };
 1762        let style = window.text_style();
 1763        let font_size = style.font_size.to_pixels(window.rem_size());
 1764        let editor = cx.entity().downgrade();
 1765        let fold_placeholder = FoldPlaceholder {
 1766            constrain_width: false,
 1767            render: Arc::new(move |fold_id, fold_range, cx| {
 1768                let editor = editor.clone();
 1769                div()
 1770                    .id(fold_id)
 1771                    .bg(cx.theme().colors().ghost_element_background)
 1772                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1773                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1774                    .rounded_xs()
 1775                    .size_full()
 1776                    .cursor_pointer()
 1777                    .child("")
 1778                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1779                    .on_click(move |_, _window, cx| {
 1780                        editor
 1781                            .update(cx, |editor, cx| {
 1782                                editor.unfold_ranges(
 1783                                    &[fold_range.start..fold_range.end],
 1784                                    true,
 1785                                    false,
 1786                                    cx,
 1787                                );
 1788                                cx.stop_propagation();
 1789                            })
 1790                            .ok();
 1791                    })
 1792                    .into_any()
 1793            }),
 1794            merge_adjacent: true,
 1795            ..FoldPlaceholder::default()
 1796        };
 1797        let display_map = display_map.unwrap_or_else(|| {
 1798            cx.new(|cx| {
 1799                DisplayMap::new(
 1800                    multi_buffer.clone(),
 1801                    style.font(),
 1802                    font_size,
 1803                    None,
 1804                    FILE_HEADER_HEIGHT,
 1805                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1806                    fold_placeholder,
 1807                    diagnostics_max_severity,
 1808                    cx,
 1809                )
 1810            })
 1811        });
 1812
 1813        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1814
 1815        let blink_manager = cx.new(|cx| {
 1816            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1817            if is_minimap {
 1818                blink_manager.disable(cx);
 1819            }
 1820            blink_manager
 1821        });
 1822
 1823        let soft_wrap_mode_override =
 1824            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1825
 1826        let mut project_subscriptions = Vec::new();
 1827        if full_mode && let Some(project) = project.as_ref() {
 1828            project_subscriptions.push(cx.subscribe_in(
 1829                project,
 1830                window,
 1831                |editor, _, event, window, cx| match event {
 1832                    project::Event::RefreshCodeLens => {
 1833                        // we always query lens with actions, without storing them, always refreshing them
 1834                    }
 1835                    project::Event::RefreshInlayHints {
 1836                        server_id,
 1837                        request_id,
 1838                    } => {
 1839                        editor.refresh_inlay_hints(
 1840                            InlayHintRefreshReason::RefreshRequested {
 1841                                server_id: *server_id,
 1842                                request_id: *request_id,
 1843                            },
 1844                            cx,
 1845                        );
 1846                    }
 1847                    project::Event::LanguageServerRemoved(..) => {
 1848                        if editor.tasks_update_task.is_none() {
 1849                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1850                        }
 1851                        editor.registered_buffers.clear();
 1852                        editor.register_visible_buffers(cx);
 1853                    }
 1854                    project::Event::LanguageServerAdded(..) => {
 1855                        if editor.tasks_update_task.is_none() {
 1856                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1857                        }
 1858                    }
 1859                    project::Event::SnippetEdit(id, snippet_edits) => {
 1860                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1861                            let focus_handle = editor.focus_handle(cx);
 1862                            if focus_handle.is_focused(window) {
 1863                                let snapshot = buffer.read(cx).snapshot();
 1864                                for (range, snippet) in snippet_edits {
 1865                                    let editor_range =
 1866                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1867                                    editor
 1868                                        .insert_snippet(
 1869                                            &[editor_range],
 1870                                            snippet.clone(),
 1871                                            window,
 1872                                            cx,
 1873                                        )
 1874                                        .ok();
 1875                                }
 1876                            }
 1877                        }
 1878                    }
 1879                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1880                        let buffer_id = *buffer_id;
 1881                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1882                            editor.register_buffer(buffer_id, cx);
 1883                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1884                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1885                            refresh_linked_ranges(editor, window, cx);
 1886                            editor.refresh_code_actions(window, cx);
 1887                            editor.refresh_document_highlights(cx);
 1888                        }
 1889                    }
 1890
 1891                    project::Event::EntryRenamed(transaction) => {
 1892                        let Some(workspace) = editor.workspace() else {
 1893                            return;
 1894                        };
 1895                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1896                        else {
 1897                            return;
 1898                        };
 1899                        if active_editor.entity_id() == cx.entity_id() {
 1900                            let edited_buffers_already_open = {
 1901                                let other_editors: Vec<Entity<Editor>> = workspace
 1902                                    .read(cx)
 1903                                    .panes()
 1904                                    .iter()
 1905                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1906                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1907                                    .collect();
 1908
 1909                                transaction.0.keys().all(|buffer| {
 1910                                    other_editors.iter().any(|editor| {
 1911                                        let multi_buffer = editor.read(cx).buffer();
 1912                                        multi_buffer.read(cx).is_singleton()
 1913                                            && multi_buffer.read(cx).as_singleton().map_or(
 1914                                                false,
 1915                                                |singleton| {
 1916                                                    singleton.entity_id() == buffer.entity_id()
 1917                                                },
 1918                                            )
 1919                                    })
 1920                                })
 1921                            };
 1922
 1923                            if !edited_buffers_already_open {
 1924                                let workspace = workspace.downgrade();
 1925                                let transaction = transaction.clone();
 1926                                cx.defer_in(window, move |_, window, cx| {
 1927                                    cx.spawn_in(window, async move |editor, cx| {
 1928                                        Self::open_project_transaction(
 1929                                            &editor,
 1930                                            workspace,
 1931                                            transaction,
 1932                                            "Rename".to_string(),
 1933                                            cx,
 1934                                        )
 1935                                        .await
 1936                                        .ok()
 1937                                    })
 1938                                    .detach();
 1939                                });
 1940                            }
 1941                        }
 1942                    }
 1943
 1944                    _ => {}
 1945                },
 1946            ));
 1947            if let Some(task_inventory) = project
 1948                .read(cx)
 1949                .task_store()
 1950                .read(cx)
 1951                .task_inventory()
 1952                .cloned()
 1953            {
 1954                project_subscriptions.push(cx.observe_in(
 1955                    &task_inventory,
 1956                    window,
 1957                    |editor, _, window, cx| {
 1958                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1959                    },
 1960                ));
 1961            };
 1962
 1963            project_subscriptions.push(cx.subscribe_in(
 1964                &project.read(cx).breakpoint_store(),
 1965                window,
 1966                |editor, _, event, window, cx| match event {
 1967                    BreakpointStoreEvent::ClearDebugLines => {
 1968                        editor.clear_row_highlights::<ActiveDebugLine>();
 1969                        editor.refresh_inline_values(cx);
 1970                    }
 1971                    BreakpointStoreEvent::SetDebugLine => {
 1972                        if editor.go_to_active_debug_line(window, cx) {
 1973                            cx.stop_propagation();
 1974                        }
 1975
 1976                        editor.refresh_inline_values(cx);
 1977                    }
 1978                    _ => {}
 1979                },
 1980            ));
 1981            let git_store = project.read(cx).git_store().clone();
 1982            let project = project.clone();
 1983            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1984                if let GitStoreEvent::RepositoryAdded = event {
 1985                    this.load_diff_task = Some(
 1986                        update_uncommitted_diff_for_buffer(
 1987                            cx.entity(),
 1988                            &project,
 1989                            this.buffer.read(cx).all_buffers(),
 1990                            this.buffer.clone(),
 1991                            cx,
 1992                        )
 1993                        .shared(),
 1994                    );
 1995                }
 1996            }));
 1997        }
 1998
 1999        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2000
 2001        let inlay_hint_settings =
 2002            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2003        let focus_handle = cx.focus_handle();
 2004        if !is_minimap {
 2005            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2006                .detach();
 2007            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2008                .detach();
 2009            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2010                .detach();
 2011            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2012                .detach();
 2013            cx.observe_pending_input(window, Self::observe_pending_input)
 2014                .detach();
 2015        }
 2016
 2017        let show_indent_guides =
 2018            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2019                Some(false)
 2020            } else {
 2021                None
 2022            };
 2023
 2024        let breakpoint_store = match (&mode, project.as_ref()) {
 2025            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2026            _ => None,
 2027        };
 2028
 2029        let mut code_action_providers = Vec::new();
 2030        let mut load_uncommitted_diff = None;
 2031        if let Some(project) = project.clone() {
 2032            load_uncommitted_diff = Some(
 2033                update_uncommitted_diff_for_buffer(
 2034                    cx.entity(),
 2035                    &project,
 2036                    multi_buffer.read(cx).all_buffers(),
 2037                    multi_buffer.clone(),
 2038                    cx,
 2039                )
 2040                .shared(),
 2041            );
 2042            code_action_providers.push(Rc::new(project) as Rc<_>);
 2043        }
 2044
 2045        let mut editor = Self {
 2046            focus_handle,
 2047            show_cursor_when_unfocused: false,
 2048            last_focused_descendant: None,
 2049            buffer: multi_buffer.clone(),
 2050            display_map: display_map.clone(),
 2051            placeholder_display_map: None,
 2052            selections,
 2053            scroll_manager: ScrollManager::new(cx),
 2054            columnar_selection_state: None,
 2055            add_selections_state: None,
 2056            select_next_state: None,
 2057            select_prev_state: None,
 2058            selection_history: SelectionHistory::default(),
 2059            defer_selection_effects: false,
 2060            deferred_selection_effects_state: None,
 2061            autoclose_regions: Vec::new(),
 2062            snippet_stack: InvalidationStack::default(),
 2063            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2064            ime_transaction: None,
 2065            active_diagnostics: ActiveDiagnostic::None,
 2066            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2067            inline_diagnostics_update: Task::ready(()),
 2068            inline_diagnostics: Vec::new(),
 2069            soft_wrap_mode_override,
 2070            diagnostics_max_severity,
 2071            hard_wrap: None,
 2072            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2073            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2074            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2075            project,
 2076            blink_manager: blink_manager.clone(),
 2077            show_local_selections: true,
 2078            show_scrollbars: ScrollbarAxes {
 2079                horizontal: full_mode,
 2080                vertical: full_mode,
 2081            },
 2082            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2083            offset_content: !matches!(mode, EditorMode::SingleLine),
 2084            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2085            show_gutter: full_mode,
 2086            show_line_numbers: (!full_mode).then_some(false),
 2087            use_relative_line_numbers: None,
 2088            disable_expand_excerpt_buttons: !full_mode,
 2089            show_git_diff_gutter: None,
 2090            show_code_actions: None,
 2091            show_runnables: None,
 2092            show_breakpoints: None,
 2093            show_wrap_guides: None,
 2094            show_indent_guides,
 2095            highlight_order: 0,
 2096            highlighted_rows: HashMap::default(),
 2097            background_highlights: HashMap::default(),
 2098            gutter_highlights: HashMap::default(),
 2099            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2100            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2101            nav_history: None,
 2102            context_menu: RefCell::new(None),
 2103            context_menu_options: None,
 2104            mouse_context_menu: None,
 2105            completion_tasks: Vec::new(),
 2106            inline_blame_popover: None,
 2107            inline_blame_popover_show_task: None,
 2108            signature_help_state: SignatureHelpState::default(),
 2109            auto_signature_help: None,
 2110            find_all_references_task_sources: Vec::new(),
 2111            next_completion_id: 0,
 2112            next_inlay_id: 0,
 2113            code_action_providers,
 2114            available_code_actions: None,
 2115            code_actions_task: None,
 2116            quick_selection_highlight_task: None,
 2117            debounced_selection_highlight_task: None,
 2118            document_highlights_task: None,
 2119            linked_editing_range_task: None,
 2120            pending_rename: None,
 2121            searchable: !is_minimap,
 2122            cursor_shape: EditorSettings::get_global(cx)
 2123                .cursor_shape
 2124                .unwrap_or_default(),
 2125            current_line_highlight: None,
 2126            autoindent_mode: Some(AutoindentMode::EachLine),
 2127
 2128            workspace: None,
 2129            input_enabled: !is_minimap,
 2130            use_modal_editing: full_mode,
 2131            read_only: is_minimap,
 2132            use_autoclose: true,
 2133            use_auto_surround: true,
 2134            auto_replace_emoji_shortcode: false,
 2135            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2136            leader_id: None,
 2137            remote_id: None,
 2138            hover_state: HoverState::default(),
 2139            pending_mouse_down: None,
 2140            hovered_link_state: None,
 2141            edit_prediction_provider: None,
 2142            active_edit_prediction: None,
 2143            stale_edit_prediction_in_menu: None,
 2144            edit_prediction_preview: EditPredictionPreview::Inactive {
 2145                released_too_fast: false,
 2146            },
 2147            inline_diagnostics_enabled: full_mode,
 2148            diagnostics_enabled: full_mode,
 2149            word_completions_enabled: full_mode,
 2150            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2151            gutter_hovered: false,
 2152            pixel_position_of_newest_cursor: None,
 2153            last_bounds: None,
 2154            last_position_map: None,
 2155            expect_bounds_change: None,
 2156            gutter_dimensions: GutterDimensions::default(),
 2157            style: None,
 2158            show_cursor_names: false,
 2159            hovered_cursors: HashMap::default(),
 2160            next_editor_action_id: EditorActionId::default(),
 2161            editor_actions: Rc::default(),
 2162            edit_predictions_hidden_for_vim_mode: false,
 2163            show_edit_predictions_override: None,
 2164            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2165            edit_prediction_settings: EditPredictionSettings::Disabled,
 2166            edit_prediction_indent_conflict: false,
 2167            edit_prediction_requires_modifier_in_indent_conflict: true,
 2168            custom_context_menu: None,
 2169            show_git_blame_gutter: false,
 2170            show_git_blame_inline: false,
 2171            show_selection_menu: None,
 2172            show_git_blame_inline_delay_task: None,
 2173            git_blame_inline_enabled: full_mode
 2174                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2175            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2176            serialize_dirty_buffers: !is_minimap
 2177                && ProjectSettings::get_global(cx)
 2178                    .session
 2179                    .restore_unsaved_buffers,
 2180            blame: None,
 2181            blame_subscription: None,
 2182            tasks: BTreeMap::default(),
 2183
 2184            breakpoint_store,
 2185            gutter_breakpoint_indicator: (None, None),
 2186            hovered_diff_hunk_row: None,
 2187            _subscriptions: (!is_minimap)
 2188                .then(|| {
 2189                    vec![
 2190                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2191                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2192                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2193                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2194                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2195                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2196                        cx.observe_window_activation(window, |editor, window, cx| {
 2197                            let active = window.is_window_active();
 2198                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2199                                if active {
 2200                                    blink_manager.enable(cx);
 2201                                } else {
 2202                                    blink_manager.disable(cx);
 2203                                }
 2204                            });
 2205                            if active {
 2206                                editor.show_mouse_cursor(cx);
 2207                            }
 2208                        }),
 2209                    ]
 2210                })
 2211                .unwrap_or_default(),
 2212            tasks_update_task: None,
 2213            pull_diagnostics_task: Task::ready(()),
 2214            colors: None,
 2215            refresh_colors_task: Task::ready(()),
 2216            inlay_hints: None,
 2217            next_color_inlay_id: 0,
 2218            post_scroll_update: Task::ready(()),
 2219            linked_edit_ranges: Default::default(),
 2220            in_project_search: false,
 2221            previous_search_ranges: None,
 2222            breadcrumb_header: None,
 2223            focused_block: None,
 2224            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2225            addons: HashMap::default(),
 2226            registered_buffers: HashMap::default(),
 2227            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2228            selection_mark_mode: false,
 2229            toggle_fold_multiple_buffers: Task::ready(()),
 2230            serialize_selections: Task::ready(()),
 2231            serialize_folds: Task::ready(()),
 2232            text_style_refinement: None,
 2233            load_diff_task: load_uncommitted_diff,
 2234            temporary_diff_override: false,
 2235            mouse_cursor_hidden: false,
 2236            minimap: None,
 2237            hide_mouse_mode: EditorSettings::get_global(cx)
 2238                .hide_mouse
 2239                .unwrap_or_default(),
 2240            change_list: ChangeList::new(),
 2241            mode,
 2242            selection_drag_state: SelectionDragState::None,
 2243            folding_newlines: Task::ready(()),
 2244            lookup_key: None,
 2245        };
 2246
 2247        if is_minimap {
 2248            return editor;
 2249        }
 2250
 2251        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2252            editor
 2253                ._subscriptions
 2254                .push(cx.observe(breakpoints, |_, _, cx| {
 2255                    cx.notify();
 2256                }));
 2257        }
 2258        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2259        editor._subscriptions.extend(project_subscriptions);
 2260
 2261        editor._subscriptions.push(cx.subscribe_in(
 2262            &cx.entity(),
 2263            window,
 2264            |editor, _, e: &EditorEvent, window, cx| match e {
 2265                EditorEvent::ScrollPositionChanged { local, .. } => {
 2266                    if *local {
 2267                        let new_anchor = editor.scroll_manager.anchor();
 2268                        let snapshot = editor.snapshot(window, cx);
 2269                        editor.update_restoration_data(cx, move |data| {
 2270                            data.scroll_position = (
 2271                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2272                                new_anchor.offset,
 2273                            );
 2274                        });
 2275                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2276                        editor.inline_blame_popover.take();
 2277                    }
 2278                }
 2279                EditorEvent::Edited { .. } => {
 2280                    if vim_flavor(cx).is_none() {
 2281                        let display_map = editor.display_snapshot(cx);
 2282                        let selections = editor.selections.all_adjusted_display(&display_map);
 2283                        let pop_state = editor
 2284                            .change_list
 2285                            .last()
 2286                            .map(|previous| {
 2287                                previous.len() == selections.len()
 2288                                    && previous.iter().enumerate().all(|(ix, p)| {
 2289                                        p.to_display_point(&display_map).row()
 2290                                            == selections[ix].head().row()
 2291                                    })
 2292                            })
 2293                            .unwrap_or(false);
 2294                        let new_positions = selections
 2295                            .into_iter()
 2296                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2297                            .collect();
 2298                        editor
 2299                            .change_list
 2300                            .push_to_change_list(pop_state, new_positions);
 2301                    }
 2302                }
 2303                _ => (),
 2304            },
 2305        ));
 2306
 2307        if let Some(dap_store) = editor
 2308            .project
 2309            .as_ref()
 2310            .map(|project| project.read(cx).dap_store())
 2311        {
 2312            let weak_editor = cx.weak_entity();
 2313
 2314            editor
 2315                ._subscriptions
 2316                .push(
 2317                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2318                        let session_entity = cx.entity();
 2319                        weak_editor
 2320                            .update(cx, |editor, cx| {
 2321                                editor._subscriptions.push(
 2322                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2323                                );
 2324                            })
 2325                            .ok();
 2326                    }),
 2327                );
 2328
 2329            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2330                editor
 2331                    ._subscriptions
 2332                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2333            }
 2334        }
 2335
 2336        // skip adding the initial selection to selection history
 2337        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2338        editor.end_selection(window, cx);
 2339        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2340
 2341        editor.scroll_manager.show_scrollbars(window, cx);
 2342        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2343
 2344        if full_mode {
 2345            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2346            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2347
 2348            if editor.git_blame_inline_enabled {
 2349                editor.start_git_blame_inline(false, window, cx);
 2350            }
 2351
 2352            editor.go_to_active_debug_line(window, cx);
 2353
 2354            editor.minimap =
 2355                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2356            editor.colors = Some(LspColorData::new(cx));
 2357            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2358
 2359            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2360                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2361            }
 2362            editor.update_lsp_data(None, window, cx);
 2363            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2364        }
 2365
 2366        editor
 2367    }
 2368
 2369    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2370        self.selections.display_map(cx)
 2371    }
 2372
 2373    pub fn deploy_mouse_context_menu(
 2374        &mut self,
 2375        position: gpui::Point<Pixels>,
 2376        context_menu: Entity<ContextMenu>,
 2377        window: &mut Window,
 2378        cx: &mut Context<Self>,
 2379    ) {
 2380        self.mouse_context_menu = Some(MouseContextMenu::new(
 2381            self,
 2382            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2383            context_menu,
 2384            window,
 2385            cx,
 2386        ));
 2387    }
 2388
 2389    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2390        self.mouse_context_menu
 2391            .as_ref()
 2392            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2393    }
 2394
 2395    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2396        if self
 2397            .selections
 2398            .pending_anchor()
 2399            .is_some_and(|pending_selection| {
 2400                let snapshot = self.buffer().read(cx).snapshot(cx);
 2401                pending_selection.range().includes(range, &snapshot)
 2402            })
 2403        {
 2404            return true;
 2405        }
 2406
 2407        self.selections
 2408            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2409            .into_iter()
 2410            .any(|selection| {
 2411                // This is needed to cover a corner case, if we just check for an existing
 2412                // selection in the fold range, having a cursor at the start of the fold
 2413                // marks it as selected. Non-empty selections don't cause this.
 2414                let length = selection.end - selection.start;
 2415                length > 0
 2416            })
 2417    }
 2418
 2419    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2420        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2421    }
 2422
 2423    fn key_context_internal(
 2424        &self,
 2425        has_active_edit_prediction: bool,
 2426        window: &mut Window,
 2427        cx: &mut App,
 2428    ) -> KeyContext {
 2429        let mut key_context = KeyContext::new_with_defaults();
 2430        key_context.add("Editor");
 2431        let mode = match self.mode {
 2432            EditorMode::SingleLine => "single_line",
 2433            EditorMode::AutoHeight { .. } => "auto_height",
 2434            EditorMode::Minimap { .. } => "minimap",
 2435            EditorMode::Full { .. } => "full",
 2436        };
 2437
 2438        if EditorSettings::jupyter_enabled(cx) {
 2439            key_context.add("jupyter");
 2440        }
 2441
 2442        key_context.set("mode", mode);
 2443        if self.pending_rename.is_some() {
 2444            key_context.add("renaming");
 2445        }
 2446
 2447        if !self.snippet_stack.is_empty() {
 2448            key_context.add("in_snippet");
 2449        }
 2450
 2451        match self.context_menu.borrow().as_ref() {
 2452            Some(CodeContextMenu::Completions(menu)) => {
 2453                if menu.visible() {
 2454                    key_context.add("menu");
 2455                    key_context.add("showing_completions");
 2456                }
 2457            }
 2458            Some(CodeContextMenu::CodeActions(menu)) => {
 2459                if menu.visible() {
 2460                    key_context.add("menu");
 2461                    key_context.add("showing_code_actions")
 2462                }
 2463            }
 2464            None => {}
 2465        }
 2466
 2467        if self.signature_help_state.has_multiple_signatures() {
 2468            key_context.add("showing_signature_help");
 2469        }
 2470
 2471        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2472        if !self.focus_handle(cx).contains_focused(window, cx)
 2473            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2474        {
 2475            for addon in self.addons.values() {
 2476                addon.extend_key_context(&mut key_context, cx)
 2477            }
 2478        }
 2479
 2480        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2481            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2482                Some(
 2483                    file.full_path(cx)
 2484                        .extension()?
 2485                        .to_string_lossy()
 2486                        .into_owned(),
 2487                )
 2488            }) {
 2489                key_context.set("extension", extension);
 2490            }
 2491        } else {
 2492            key_context.add("multibuffer");
 2493        }
 2494
 2495        if has_active_edit_prediction {
 2496            if self.edit_prediction_in_conflict() {
 2497                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2498            } else {
 2499                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2500                key_context.add("copilot_suggestion");
 2501            }
 2502        }
 2503
 2504        if self.selection_mark_mode {
 2505            key_context.add("selection_mode");
 2506        }
 2507
 2508        let disjoint = self.selections.disjoint_anchors();
 2509        let snapshot = self.snapshot(window, cx);
 2510        let snapshot = snapshot.buffer_snapshot();
 2511        if self.mode == EditorMode::SingleLine
 2512            && let [selection] = disjoint
 2513            && selection.start == selection.end
 2514            && selection.end.to_offset(snapshot) == snapshot.len()
 2515        {
 2516            key_context.add("end_of_input");
 2517        }
 2518
 2519        key_context
 2520    }
 2521
 2522    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2523        self.last_bounds.as_ref()
 2524    }
 2525
 2526    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2527        if self.mouse_cursor_hidden {
 2528            self.mouse_cursor_hidden = false;
 2529            cx.notify();
 2530        }
 2531    }
 2532
 2533    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2534        let hide_mouse_cursor = match origin {
 2535            HideMouseCursorOrigin::TypingAction => {
 2536                matches!(
 2537                    self.hide_mouse_mode,
 2538                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2539                )
 2540            }
 2541            HideMouseCursorOrigin::MovementAction => {
 2542                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2543            }
 2544        };
 2545        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2546            self.mouse_cursor_hidden = hide_mouse_cursor;
 2547            cx.notify();
 2548        }
 2549    }
 2550
 2551    pub fn edit_prediction_in_conflict(&self) -> bool {
 2552        if !self.show_edit_predictions_in_menu() {
 2553            return false;
 2554        }
 2555
 2556        let showing_completions = self
 2557            .context_menu
 2558            .borrow()
 2559            .as_ref()
 2560            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2561
 2562        showing_completions
 2563            || self.edit_prediction_requires_modifier()
 2564            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2565            // bindings to insert tab characters.
 2566            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2567    }
 2568
 2569    pub fn accept_edit_prediction_keybind(
 2570        &self,
 2571        accept_partial: bool,
 2572        window: &mut Window,
 2573        cx: &mut App,
 2574    ) -> AcceptEditPredictionBinding {
 2575        let key_context = self.key_context_internal(true, window, cx);
 2576        let in_conflict = self.edit_prediction_in_conflict();
 2577
 2578        let bindings = if accept_partial {
 2579            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2580        } else {
 2581            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2582        };
 2583
 2584        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2585        // just the first one.
 2586        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2587            !in_conflict
 2588                || binding
 2589                    .keystrokes()
 2590                    .first()
 2591                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2592        }))
 2593    }
 2594
 2595    pub fn new_file(
 2596        workspace: &mut Workspace,
 2597        _: &workspace::NewFile,
 2598        window: &mut Window,
 2599        cx: &mut Context<Workspace>,
 2600    ) {
 2601        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2602            "Failed to create buffer",
 2603            window,
 2604            cx,
 2605            |e, _, _| match e.error_code() {
 2606                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2607                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2608                e.error_tag("required").unwrap_or("the latest version")
 2609            )),
 2610                _ => None,
 2611            },
 2612        );
 2613    }
 2614
 2615    pub fn new_in_workspace(
 2616        workspace: &mut Workspace,
 2617        window: &mut Window,
 2618        cx: &mut Context<Workspace>,
 2619    ) -> Task<Result<Entity<Editor>>> {
 2620        let project = workspace.project().clone();
 2621        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2622
 2623        cx.spawn_in(window, async move |workspace, cx| {
 2624            let buffer = create.await?;
 2625            workspace.update_in(cx, |workspace, window, cx| {
 2626                let editor =
 2627                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2628                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2629                editor
 2630            })
 2631        })
 2632    }
 2633
 2634    fn new_file_vertical(
 2635        workspace: &mut Workspace,
 2636        _: &workspace::NewFileSplitVertical,
 2637        window: &mut Window,
 2638        cx: &mut Context<Workspace>,
 2639    ) {
 2640        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2641    }
 2642
 2643    fn new_file_horizontal(
 2644        workspace: &mut Workspace,
 2645        _: &workspace::NewFileSplitHorizontal,
 2646        window: &mut Window,
 2647        cx: &mut Context<Workspace>,
 2648    ) {
 2649        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2650    }
 2651
 2652    fn new_file_split(
 2653        workspace: &mut Workspace,
 2654        action: &workspace::NewFileSplit,
 2655        window: &mut Window,
 2656        cx: &mut Context<Workspace>,
 2657    ) {
 2658        Self::new_file_in_direction(workspace, action.0, window, cx)
 2659    }
 2660
 2661    fn new_file_in_direction(
 2662        workspace: &mut Workspace,
 2663        direction: SplitDirection,
 2664        window: &mut Window,
 2665        cx: &mut Context<Workspace>,
 2666    ) {
 2667        let project = workspace.project().clone();
 2668        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2669
 2670        cx.spawn_in(window, async move |workspace, cx| {
 2671            let buffer = create.await?;
 2672            workspace.update_in(cx, move |workspace, window, cx| {
 2673                workspace.split_item(
 2674                    direction,
 2675                    Box::new(
 2676                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2677                    ),
 2678                    window,
 2679                    cx,
 2680                )
 2681            })?;
 2682            anyhow::Ok(())
 2683        })
 2684        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2685            match e.error_code() {
 2686                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2687                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2688                e.error_tag("required").unwrap_or("the latest version")
 2689            )),
 2690                _ => None,
 2691            }
 2692        });
 2693    }
 2694
 2695    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2696        self.leader_id
 2697    }
 2698
 2699    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2700        &self.buffer
 2701    }
 2702
 2703    pub fn project(&self) -> Option<&Entity<Project>> {
 2704        self.project.as_ref()
 2705    }
 2706
 2707    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2708        self.workspace.as_ref()?.0.upgrade()
 2709    }
 2710
 2711    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2712        self.buffer().read(cx).title(cx)
 2713    }
 2714
 2715    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2716        let git_blame_gutter_max_author_length = self
 2717            .render_git_blame_gutter(cx)
 2718            .then(|| {
 2719                if let Some(blame) = self.blame.as_ref() {
 2720                    let max_author_length =
 2721                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2722                    Some(max_author_length)
 2723                } else {
 2724                    None
 2725                }
 2726            })
 2727            .flatten();
 2728
 2729        EditorSnapshot {
 2730            mode: self.mode.clone(),
 2731            show_gutter: self.show_gutter,
 2732            show_line_numbers: self.show_line_numbers,
 2733            show_git_diff_gutter: self.show_git_diff_gutter,
 2734            show_code_actions: self.show_code_actions,
 2735            show_runnables: self.show_runnables,
 2736            show_breakpoints: self.show_breakpoints,
 2737            git_blame_gutter_max_author_length,
 2738            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2739            placeholder_display_snapshot: self
 2740                .placeholder_display_map
 2741                .as_ref()
 2742                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2743            scroll_anchor: self.scroll_manager.anchor(),
 2744            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2745            is_focused: self.focus_handle.is_focused(window),
 2746            current_line_highlight: self
 2747                .current_line_highlight
 2748                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2749            gutter_hovered: self.gutter_hovered,
 2750        }
 2751    }
 2752
 2753    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2754        self.buffer.read(cx).language_at(point, cx)
 2755    }
 2756
 2757    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2758        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2759    }
 2760
 2761    pub fn active_excerpt(
 2762        &self,
 2763        cx: &App,
 2764    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2765        self.buffer
 2766            .read(cx)
 2767            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2768    }
 2769
 2770    pub fn mode(&self) -> &EditorMode {
 2771        &self.mode
 2772    }
 2773
 2774    pub fn set_mode(&mut self, mode: EditorMode) {
 2775        self.mode = mode;
 2776    }
 2777
 2778    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2779        self.collaboration_hub.as_deref()
 2780    }
 2781
 2782    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2783        self.collaboration_hub = Some(hub);
 2784    }
 2785
 2786    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2787        self.in_project_search = in_project_search;
 2788    }
 2789
 2790    pub fn set_custom_context_menu(
 2791        &mut self,
 2792        f: impl 'static
 2793        + Fn(
 2794            &mut Self,
 2795            DisplayPoint,
 2796            &mut Window,
 2797            &mut Context<Self>,
 2798        ) -> Option<Entity<ui::ContextMenu>>,
 2799    ) {
 2800        self.custom_context_menu = Some(Box::new(f))
 2801    }
 2802
 2803    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2804        self.completion_provider = provider;
 2805    }
 2806
 2807    #[cfg(any(test, feature = "test-support"))]
 2808    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2809        self.completion_provider.clone()
 2810    }
 2811
 2812    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2813        self.semantics_provider.clone()
 2814    }
 2815
 2816    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2817        self.semantics_provider = provider;
 2818    }
 2819
 2820    pub fn set_edit_prediction_provider<T>(
 2821        &mut self,
 2822        provider: Option<Entity<T>>,
 2823        window: &mut Window,
 2824        cx: &mut Context<Self>,
 2825    ) where
 2826        T: EditPredictionProvider,
 2827    {
 2828        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2829            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2830                if this.focus_handle.is_focused(window) {
 2831                    this.update_visible_edit_prediction(window, cx);
 2832                }
 2833            }),
 2834            provider: Arc::new(provider),
 2835        });
 2836        self.update_edit_prediction_settings(cx);
 2837        self.refresh_edit_prediction(false, false, window, cx);
 2838    }
 2839
 2840    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2841        self.placeholder_display_map
 2842            .as_ref()
 2843            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2844    }
 2845
 2846    pub fn set_placeholder_text(
 2847        &mut self,
 2848        placeholder_text: &str,
 2849        window: &mut Window,
 2850        cx: &mut Context<Self>,
 2851    ) {
 2852        let multibuffer = cx
 2853            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2854
 2855        let style = window.text_style();
 2856
 2857        self.placeholder_display_map = Some(cx.new(|cx| {
 2858            DisplayMap::new(
 2859                multibuffer,
 2860                style.font(),
 2861                style.font_size.to_pixels(window.rem_size()),
 2862                None,
 2863                FILE_HEADER_HEIGHT,
 2864                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2865                Default::default(),
 2866                DiagnosticSeverity::Off,
 2867                cx,
 2868            )
 2869        }));
 2870        cx.notify();
 2871    }
 2872
 2873    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2874        self.cursor_shape = cursor_shape;
 2875
 2876        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2877        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2878
 2879        cx.notify();
 2880    }
 2881
 2882    pub fn set_current_line_highlight(
 2883        &mut self,
 2884        current_line_highlight: Option<CurrentLineHighlight>,
 2885    ) {
 2886        self.current_line_highlight = current_line_highlight;
 2887    }
 2888
 2889    pub fn range_for_match<T: std::marker::Copy>(
 2890        &self,
 2891        range: &Range<T>,
 2892        collapse: bool,
 2893    ) -> Range<T> {
 2894        if collapse {
 2895            return range.start..range.start;
 2896        }
 2897        range.clone()
 2898    }
 2899
 2900    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2901        if self.display_map.read(cx).clip_at_line_ends != clip {
 2902            self.display_map
 2903                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2904        }
 2905    }
 2906
 2907    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2908        self.input_enabled = input_enabled;
 2909    }
 2910
 2911    pub fn set_edit_predictions_hidden_for_vim_mode(
 2912        &mut self,
 2913        hidden: bool,
 2914        window: &mut Window,
 2915        cx: &mut Context<Self>,
 2916    ) {
 2917        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2918            self.edit_predictions_hidden_for_vim_mode = hidden;
 2919            if hidden {
 2920                self.update_visible_edit_prediction(window, cx);
 2921            } else {
 2922                self.refresh_edit_prediction(true, false, window, cx);
 2923            }
 2924        }
 2925    }
 2926
 2927    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2928        self.menu_edit_predictions_policy = value;
 2929    }
 2930
 2931    pub fn set_autoindent(&mut self, autoindent: bool) {
 2932        if autoindent {
 2933            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2934        } else {
 2935            self.autoindent_mode = None;
 2936        }
 2937    }
 2938
 2939    pub fn read_only(&self, cx: &App) -> bool {
 2940        self.read_only || self.buffer.read(cx).read_only()
 2941    }
 2942
 2943    pub fn set_read_only(&mut self, read_only: bool) {
 2944        self.read_only = read_only;
 2945    }
 2946
 2947    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2948        self.use_autoclose = autoclose;
 2949    }
 2950
 2951    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2952        self.use_auto_surround = auto_surround;
 2953    }
 2954
 2955    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2956        self.auto_replace_emoji_shortcode = auto_replace;
 2957    }
 2958
 2959    pub fn toggle_edit_predictions(
 2960        &mut self,
 2961        _: &ToggleEditPrediction,
 2962        window: &mut Window,
 2963        cx: &mut Context<Self>,
 2964    ) {
 2965        if self.show_edit_predictions_override.is_some() {
 2966            self.set_show_edit_predictions(None, window, cx);
 2967        } else {
 2968            let show_edit_predictions = !self.edit_predictions_enabled();
 2969            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2970        }
 2971    }
 2972
 2973    pub fn set_show_edit_predictions(
 2974        &mut self,
 2975        show_edit_predictions: Option<bool>,
 2976        window: &mut Window,
 2977        cx: &mut Context<Self>,
 2978    ) {
 2979        self.show_edit_predictions_override = show_edit_predictions;
 2980        self.update_edit_prediction_settings(cx);
 2981
 2982        if let Some(false) = show_edit_predictions {
 2983            self.discard_edit_prediction(false, cx);
 2984        } else {
 2985            self.refresh_edit_prediction(false, true, window, cx);
 2986        }
 2987    }
 2988
 2989    fn edit_predictions_disabled_in_scope(
 2990        &self,
 2991        buffer: &Entity<Buffer>,
 2992        buffer_position: language::Anchor,
 2993        cx: &App,
 2994    ) -> bool {
 2995        let snapshot = buffer.read(cx).snapshot();
 2996        let settings = snapshot.settings_at(buffer_position, cx);
 2997
 2998        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2999            return false;
 3000        };
 3001
 3002        scope.override_name().is_some_and(|scope_name| {
 3003            settings
 3004                .edit_predictions_disabled_in
 3005                .iter()
 3006                .any(|s| s == scope_name)
 3007        })
 3008    }
 3009
 3010    pub fn set_use_modal_editing(&mut self, to: bool) {
 3011        self.use_modal_editing = to;
 3012    }
 3013
 3014    pub fn use_modal_editing(&self) -> bool {
 3015        self.use_modal_editing
 3016    }
 3017
 3018    fn selections_did_change(
 3019        &mut self,
 3020        local: bool,
 3021        old_cursor_position: &Anchor,
 3022        effects: SelectionEffects,
 3023        window: &mut Window,
 3024        cx: &mut Context<Self>,
 3025    ) {
 3026        window.invalidate_character_coordinates();
 3027
 3028        // Copy selections to primary selection buffer
 3029        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3030        if local {
 3031            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3032            let buffer_handle = self.buffer.read(cx).read(cx);
 3033
 3034            let mut text = String::new();
 3035            for (index, selection) in selections.iter().enumerate() {
 3036                let text_for_selection = buffer_handle
 3037                    .text_for_range(selection.start..selection.end)
 3038                    .collect::<String>();
 3039
 3040                text.push_str(&text_for_selection);
 3041                if index != selections.len() - 1 {
 3042                    text.push('\n');
 3043                }
 3044            }
 3045
 3046            if !text.is_empty() {
 3047                cx.write_to_primary(ClipboardItem::new_string(text));
 3048            }
 3049        }
 3050
 3051        let selection_anchors = self.selections.disjoint_anchors_arc();
 3052
 3053        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3054            self.buffer.update(cx, |buffer, cx| {
 3055                buffer.set_active_selections(
 3056                    &selection_anchors,
 3057                    self.selections.line_mode(),
 3058                    self.cursor_shape,
 3059                    cx,
 3060                )
 3061            });
 3062        }
 3063        let display_map = self
 3064            .display_map
 3065            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3066        let buffer = display_map.buffer_snapshot();
 3067        if self.selections.count() == 1 {
 3068            self.add_selections_state = None;
 3069        }
 3070        self.select_next_state = None;
 3071        self.select_prev_state = None;
 3072        self.select_syntax_node_history.try_clear();
 3073        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3074        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3075        self.take_rename(false, window, cx);
 3076
 3077        let newest_selection = self.selections.newest_anchor();
 3078        let new_cursor_position = newest_selection.head();
 3079        let selection_start = newest_selection.start;
 3080
 3081        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3082            self.push_to_nav_history(
 3083                *old_cursor_position,
 3084                Some(new_cursor_position.to_point(buffer)),
 3085                false,
 3086                effects.nav_history == Some(true),
 3087                cx,
 3088            );
 3089        }
 3090
 3091        if local {
 3092            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3093                self.register_buffer(buffer_id, cx);
 3094            }
 3095
 3096            let mut context_menu = self.context_menu.borrow_mut();
 3097            let completion_menu = match context_menu.as_ref() {
 3098                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3099                Some(CodeContextMenu::CodeActions(_)) => {
 3100                    *context_menu = None;
 3101                    None
 3102                }
 3103                None => None,
 3104            };
 3105            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3106            drop(context_menu);
 3107
 3108            if effects.completions
 3109                && let Some(completion_position) = completion_position
 3110            {
 3111                let start_offset = selection_start.to_offset(buffer);
 3112                let position_matches = start_offset == completion_position.to_offset(buffer);
 3113                let continue_showing = if position_matches {
 3114                    if self.snippet_stack.is_empty() {
 3115                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3116                            == Some(CharKind::Word)
 3117                    } else {
 3118                        // Snippet choices can be shown even when the cursor is in whitespace.
 3119                        // Dismissing the menu with actions like backspace is handled by
 3120                        // invalidation regions.
 3121                        true
 3122                    }
 3123                } else {
 3124                    false
 3125                };
 3126
 3127                if continue_showing {
 3128                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3129                } else {
 3130                    self.hide_context_menu(window, cx);
 3131                }
 3132            }
 3133
 3134            hide_hover(self, cx);
 3135
 3136            if old_cursor_position.to_display_point(&display_map).row()
 3137                != new_cursor_position.to_display_point(&display_map).row()
 3138            {
 3139                self.available_code_actions.take();
 3140            }
 3141            self.refresh_code_actions(window, cx);
 3142            self.refresh_document_highlights(cx);
 3143            refresh_linked_ranges(self, window, cx);
 3144
 3145            self.refresh_selected_text_highlights(false, window, cx);
 3146            self.refresh_matching_bracket_highlights(window, cx);
 3147            self.update_visible_edit_prediction(window, cx);
 3148            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3149            self.inline_blame_popover.take();
 3150            if self.git_blame_inline_enabled {
 3151                self.start_inline_blame_timer(window, cx);
 3152            }
 3153        }
 3154
 3155        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3156        cx.emit(EditorEvent::SelectionsChanged { local });
 3157
 3158        let selections = &self.selections.disjoint_anchors_arc();
 3159        if selections.len() == 1 {
 3160            cx.emit(SearchEvent::ActiveMatchChanged)
 3161        }
 3162        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3163            let inmemory_selections = selections
 3164                .iter()
 3165                .map(|s| {
 3166                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3167                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3168                })
 3169                .collect();
 3170            self.update_restoration_data(cx, |data| {
 3171                data.selections = inmemory_selections;
 3172            });
 3173
 3174            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3175                && let Some(workspace_id) =
 3176                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3177            {
 3178                let snapshot = self.buffer().read(cx).snapshot(cx);
 3179                let selections = selections.clone();
 3180                let background_executor = cx.background_executor().clone();
 3181                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3182                self.serialize_selections = cx.background_spawn(async move {
 3183                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3184                    let db_selections = selections
 3185                        .iter()
 3186                        .map(|selection| {
 3187                            (
 3188                                selection.start.to_offset(&snapshot),
 3189                                selection.end.to_offset(&snapshot),
 3190                            )
 3191                        })
 3192                        .collect();
 3193
 3194                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3195                        .await
 3196                        .with_context(|| {
 3197                            format!(
 3198                                "persisting editor selections for editor {editor_id}, \
 3199                                workspace {workspace_id:?}"
 3200                            )
 3201                        })
 3202                        .log_err();
 3203                });
 3204            }
 3205        }
 3206
 3207        cx.notify();
 3208    }
 3209
 3210    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3211        use text::ToOffset as _;
 3212        use text::ToPoint as _;
 3213
 3214        if self.mode.is_minimap()
 3215            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3216        {
 3217            return;
 3218        }
 3219
 3220        if !self.buffer().read(cx).is_singleton() {
 3221            return;
 3222        }
 3223
 3224        let display_snapshot = self
 3225            .display_map
 3226            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3227        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3228            return;
 3229        };
 3230        let inmemory_folds = display_snapshot
 3231            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3232            .map(|fold| {
 3233                fold.range.start.text_anchor.to_point(&snapshot)
 3234                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3235            })
 3236            .collect();
 3237        self.update_restoration_data(cx, |data| {
 3238            data.folds = inmemory_folds;
 3239        });
 3240
 3241        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3242            return;
 3243        };
 3244        let background_executor = cx.background_executor().clone();
 3245        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3246        let db_folds = display_snapshot
 3247            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3248            .map(|fold| {
 3249                (
 3250                    fold.range.start.text_anchor.to_offset(&snapshot),
 3251                    fold.range.end.text_anchor.to_offset(&snapshot),
 3252                )
 3253            })
 3254            .collect();
 3255        self.serialize_folds = cx.background_spawn(async move {
 3256            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3257            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3258                .await
 3259                .with_context(|| {
 3260                    format!(
 3261                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3262                    )
 3263                })
 3264                .log_err();
 3265        });
 3266    }
 3267
 3268    pub fn sync_selections(
 3269        &mut self,
 3270        other: Entity<Editor>,
 3271        cx: &mut Context<Self>,
 3272    ) -> gpui::Subscription {
 3273        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3274        if !other_selections.is_empty() {
 3275            self.selections.change_with(cx, |selections| {
 3276                selections.select_anchors(other_selections);
 3277            });
 3278        }
 3279
 3280        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3281            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3282                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3283                if other_selections.is_empty() {
 3284                    return;
 3285                }
 3286                this.selections.change_with(cx, |selections| {
 3287                    selections.select_anchors(other_selections);
 3288                });
 3289            }
 3290        });
 3291
 3292        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3293            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3294                let these_selections = this.selections.disjoint_anchors().to_vec();
 3295                if these_selections.is_empty() {
 3296                    return;
 3297                }
 3298                other.update(cx, |other_editor, cx| {
 3299                    other_editor.selections.change_with(cx, |selections| {
 3300                        selections.select_anchors(these_selections);
 3301                    })
 3302                });
 3303            }
 3304        });
 3305
 3306        Subscription::join(other_subscription, this_subscription)
 3307    }
 3308
 3309    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3310    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3311    /// effects of selection change occur at the end of the transaction.
 3312    pub fn change_selections<R>(
 3313        &mut self,
 3314        effects: SelectionEffects,
 3315        window: &mut Window,
 3316        cx: &mut Context<Self>,
 3317        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3318    ) -> R {
 3319        if let Some(state) = &mut self.deferred_selection_effects_state {
 3320            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3321            state.effects.completions = effects.completions;
 3322            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3323            let (changed, result) = self.selections.change_with(cx, change);
 3324            state.changed |= changed;
 3325            return result;
 3326        }
 3327        let mut state = DeferredSelectionEffectsState {
 3328            changed: false,
 3329            effects,
 3330            old_cursor_position: self.selections.newest_anchor().head(),
 3331            history_entry: SelectionHistoryEntry {
 3332                selections: self.selections.disjoint_anchors_arc(),
 3333                select_next_state: self.select_next_state.clone(),
 3334                select_prev_state: self.select_prev_state.clone(),
 3335                add_selections_state: self.add_selections_state.clone(),
 3336            },
 3337        };
 3338        let (changed, result) = self.selections.change_with(cx, change);
 3339        state.changed = state.changed || changed;
 3340        if self.defer_selection_effects {
 3341            self.deferred_selection_effects_state = Some(state);
 3342        } else {
 3343            self.apply_selection_effects(state, window, cx);
 3344        }
 3345        result
 3346    }
 3347
 3348    /// Defers the effects of selection change, so that the effects of multiple calls to
 3349    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3350    /// to selection history and the state of popovers based on selection position aren't
 3351    /// erroneously updated.
 3352    pub fn with_selection_effects_deferred<R>(
 3353        &mut self,
 3354        window: &mut Window,
 3355        cx: &mut Context<Self>,
 3356        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3357    ) -> R {
 3358        let already_deferred = self.defer_selection_effects;
 3359        self.defer_selection_effects = true;
 3360        let result = update(self, window, cx);
 3361        if !already_deferred {
 3362            self.defer_selection_effects = false;
 3363            if let Some(state) = self.deferred_selection_effects_state.take() {
 3364                self.apply_selection_effects(state, window, cx);
 3365            }
 3366        }
 3367        result
 3368    }
 3369
 3370    fn apply_selection_effects(
 3371        &mut self,
 3372        state: DeferredSelectionEffectsState,
 3373        window: &mut Window,
 3374        cx: &mut Context<Self>,
 3375    ) {
 3376        if state.changed {
 3377            self.selection_history.push(state.history_entry);
 3378
 3379            if let Some(autoscroll) = state.effects.scroll {
 3380                self.request_autoscroll(autoscroll, cx);
 3381            }
 3382
 3383            let old_cursor_position = &state.old_cursor_position;
 3384
 3385            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3386
 3387            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3388                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3389            }
 3390        }
 3391    }
 3392
 3393    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3394    where
 3395        I: IntoIterator<Item = (Range<S>, T)>,
 3396        S: ToOffset,
 3397        T: Into<Arc<str>>,
 3398    {
 3399        if self.read_only(cx) {
 3400            return;
 3401        }
 3402
 3403        self.buffer
 3404            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3405    }
 3406
 3407    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3408    where
 3409        I: IntoIterator<Item = (Range<S>, T)>,
 3410        S: ToOffset,
 3411        T: Into<Arc<str>>,
 3412    {
 3413        if self.read_only(cx) {
 3414            return;
 3415        }
 3416
 3417        self.buffer.update(cx, |buffer, cx| {
 3418            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3419        });
 3420    }
 3421
 3422    pub fn edit_with_block_indent<I, S, T>(
 3423        &mut self,
 3424        edits: I,
 3425        original_indent_columns: Vec<Option<u32>>,
 3426        cx: &mut Context<Self>,
 3427    ) where
 3428        I: IntoIterator<Item = (Range<S>, T)>,
 3429        S: ToOffset,
 3430        T: Into<Arc<str>>,
 3431    {
 3432        if self.read_only(cx) {
 3433            return;
 3434        }
 3435
 3436        self.buffer.update(cx, |buffer, cx| {
 3437            buffer.edit(
 3438                edits,
 3439                Some(AutoindentMode::Block {
 3440                    original_indent_columns,
 3441                }),
 3442                cx,
 3443            )
 3444        });
 3445    }
 3446
 3447    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3448        self.hide_context_menu(window, cx);
 3449
 3450        match phase {
 3451            SelectPhase::Begin {
 3452                position,
 3453                add,
 3454                click_count,
 3455            } => self.begin_selection(position, add, click_count, window, cx),
 3456            SelectPhase::BeginColumnar {
 3457                position,
 3458                goal_column,
 3459                reset,
 3460                mode,
 3461            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3462            SelectPhase::Extend {
 3463                position,
 3464                click_count,
 3465            } => self.extend_selection(position, click_count, window, cx),
 3466            SelectPhase::Update {
 3467                position,
 3468                goal_column,
 3469                scroll_delta,
 3470            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3471            SelectPhase::End => self.end_selection(window, cx),
 3472        }
 3473    }
 3474
 3475    fn extend_selection(
 3476        &mut self,
 3477        position: DisplayPoint,
 3478        click_count: usize,
 3479        window: &mut Window,
 3480        cx: &mut Context<Self>,
 3481    ) {
 3482        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3483        let tail = self.selections.newest::<usize>(&display_map).tail();
 3484        let click_count = click_count.max(match self.selections.select_mode() {
 3485            SelectMode::Character => 1,
 3486            SelectMode::Word(_) => 2,
 3487            SelectMode::Line(_) => 3,
 3488            SelectMode::All => 4,
 3489        });
 3490        self.begin_selection(position, false, click_count, window, cx);
 3491
 3492        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3493
 3494        let current_selection = match self.selections.select_mode() {
 3495            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3496            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3497        };
 3498
 3499        let mut pending_selection = self
 3500            .selections
 3501            .pending_anchor()
 3502            .cloned()
 3503            .expect("extend_selection not called with pending selection");
 3504
 3505        if pending_selection
 3506            .start
 3507            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3508            == Ordering::Greater
 3509        {
 3510            pending_selection.start = current_selection.start;
 3511        }
 3512        if pending_selection
 3513            .end
 3514            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3515            == Ordering::Less
 3516        {
 3517            pending_selection.end = current_selection.end;
 3518            pending_selection.reversed = true;
 3519        }
 3520
 3521        let mut pending_mode = self.selections.pending_mode().unwrap();
 3522        match &mut pending_mode {
 3523            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3524            _ => {}
 3525        }
 3526
 3527        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3528            SelectionEffects::scroll(Autoscroll::fit())
 3529        } else {
 3530            SelectionEffects::no_scroll()
 3531        };
 3532
 3533        self.change_selections(effects, window, cx, |s| {
 3534            s.set_pending(pending_selection.clone(), pending_mode);
 3535            s.set_is_extending(true);
 3536        });
 3537    }
 3538
 3539    fn begin_selection(
 3540        &mut self,
 3541        position: DisplayPoint,
 3542        add: bool,
 3543        click_count: usize,
 3544        window: &mut Window,
 3545        cx: &mut Context<Self>,
 3546    ) {
 3547        if !self.focus_handle.is_focused(window) {
 3548            self.last_focused_descendant = None;
 3549            window.focus(&self.focus_handle);
 3550        }
 3551
 3552        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3553        let buffer = display_map.buffer_snapshot();
 3554        let position = display_map.clip_point(position, Bias::Left);
 3555
 3556        let start;
 3557        let end;
 3558        let mode;
 3559        let mut auto_scroll;
 3560        match click_count {
 3561            1 => {
 3562                start = buffer.anchor_before(position.to_point(&display_map));
 3563                end = start;
 3564                mode = SelectMode::Character;
 3565                auto_scroll = true;
 3566            }
 3567            2 => {
 3568                let position = display_map
 3569                    .clip_point(position, Bias::Left)
 3570                    .to_offset(&display_map, Bias::Left);
 3571                let (range, _) = buffer.surrounding_word(position, None);
 3572                start = buffer.anchor_before(range.start);
 3573                end = buffer.anchor_before(range.end);
 3574                mode = SelectMode::Word(start..end);
 3575                auto_scroll = true;
 3576            }
 3577            3 => {
 3578                let position = display_map
 3579                    .clip_point(position, Bias::Left)
 3580                    .to_point(&display_map);
 3581                let line_start = display_map.prev_line_boundary(position).0;
 3582                let next_line_start = buffer.clip_point(
 3583                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3584                    Bias::Left,
 3585                );
 3586                start = buffer.anchor_before(line_start);
 3587                end = buffer.anchor_before(next_line_start);
 3588                mode = SelectMode::Line(start..end);
 3589                auto_scroll = true;
 3590            }
 3591            _ => {
 3592                start = buffer.anchor_before(0);
 3593                end = buffer.anchor_before(buffer.len());
 3594                mode = SelectMode::All;
 3595                auto_scroll = false;
 3596            }
 3597        }
 3598        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3599
 3600        let point_to_delete: Option<usize> = {
 3601            let selected_points: Vec<Selection<Point>> =
 3602                self.selections.disjoint_in_range(start..end, &display_map);
 3603
 3604            if !add || click_count > 1 {
 3605                None
 3606            } else if !selected_points.is_empty() {
 3607                Some(selected_points[0].id)
 3608            } else {
 3609                let clicked_point_already_selected =
 3610                    self.selections.disjoint_anchors().iter().find(|selection| {
 3611                        selection.start.to_point(buffer) == start.to_point(buffer)
 3612                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3613                    });
 3614
 3615                clicked_point_already_selected.map(|selection| selection.id)
 3616            }
 3617        };
 3618
 3619        let selections_count = self.selections.count();
 3620        let effects = if auto_scroll {
 3621            SelectionEffects::default()
 3622        } else {
 3623            SelectionEffects::no_scroll()
 3624        };
 3625
 3626        self.change_selections(effects, window, cx, |s| {
 3627            if let Some(point_to_delete) = point_to_delete {
 3628                s.delete(point_to_delete);
 3629
 3630                if selections_count == 1 {
 3631                    s.set_pending_anchor_range(start..end, mode);
 3632                }
 3633            } else {
 3634                if !add {
 3635                    s.clear_disjoint();
 3636                }
 3637
 3638                s.set_pending_anchor_range(start..end, mode);
 3639            }
 3640        });
 3641    }
 3642
 3643    fn begin_columnar_selection(
 3644        &mut self,
 3645        position: DisplayPoint,
 3646        goal_column: u32,
 3647        reset: bool,
 3648        mode: ColumnarMode,
 3649        window: &mut Window,
 3650        cx: &mut Context<Self>,
 3651    ) {
 3652        if !self.focus_handle.is_focused(window) {
 3653            self.last_focused_descendant = None;
 3654            window.focus(&self.focus_handle);
 3655        }
 3656
 3657        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3658
 3659        if reset {
 3660            let pointer_position = display_map
 3661                .buffer_snapshot()
 3662                .anchor_before(position.to_point(&display_map));
 3663
 3664            self.change_selections(
 3665                SelectionEffects::scroll(Autoscroll::newest()),
 3666                window,
 3667                cx,
 3668                |s| {
 3669                    s.clear_disjoint();
 3670                    s.set_pending_anchor_range(
 3671                        pointer_position..pointer_position,
 3672                        SelectMode::Character,
 3673                    );
 3674                },
 3675            );
 3676        };
 3677
 3678        let tail = self.selections.newest::<Point>(&display_map).tail();
 3679        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3680        self.columnar_selection_state = match mode {
 3681            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3682                selection_tail: selection_anchor,
 3683                display_point: if reset {
 3684                    if position.column() != goal_column {
 3685                        Some(DisplayPoint::new(position.row(), goal_column))
 3686                    } else {
 3687                        None
 3688                    }
 3689                } else {
 3690                    None
 3691                },
 3692            }),
 3693            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3694                selection_tail: selection_anchor,
 3695            }),
 3696        };
 3697
 3698        if !reset {
 3699            self.select_columns(position, goal_column, &display_map, window, cx);
 3700        }
 3701    }
 3702
 3703    fn update_selection(
 3704        &mut self,
 3705        position: DisplayPoint,
 3706        goal_column: u32,
 3707        scroll_delta: gpui::Point<f32>,
 3708        window: &mut Window,
 3709        cx: &mut Context<Self>,
 3710    ) {
 3711        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3712
 3713        if self.columnar_selection_state.is_some() {
 3714            self.select_columns(position, goal_column, &display_map, window, cx);
 3715        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3716            let buffer = display_map.buffer_snapshot();
 3717            let head;
 3718            let tail;
 3719            let mode = self.selections.pending_mode().unwrap();
 3720            match &mode {
 3721                SelectMode::Character => {
 3722                    head = position.to_point(&display_map);
 3723                    tail = pending.tail().to_point(buffer);
 3724                }
 3725                SelectMode::Word(original_range) => {
 3726                    let offset = display_map
 3727                        .clip_point(position, Bias::Left)
 3728                        .to_offset(&display_map, Bias::Left);
 3729                    let original_range = original_range.to_offset(buffer);
 3730
 3731                    let head_offset = if buffer.is_inside_word(offset, None)
 3732                        || original_range.contains(&offset)
 3733                    {
 3734                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3735                        if word_range.start < original_range.start {
 3736                            word_range.start
 3737                        } else {
 3738                            word_range.end
 3739                        }
 3740                    } else {
 3741                        offset
 3742                    };
 3743
 3744                    head = head_offset.to_point(buffer);
 3745                    if head_offset <= original_range.start {
 3746                        tail = original_range.end.to_point(buffer);
 3747                    } else {
 3748                        tail = original_range.start.to_point(buffer);
 3749                    }
 3750                }
 3751                SelectMode::Line(original_range) => {
 3752                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3753
 3754                    let position = display_map
 3755                        .clip_point(position, Bias::Left)
 3756                        .to_point(&display_map);
 3757                    let line_start = display_map.prev_line_boundary(position).0;
 3758                    let next_line_start = buffer.clip_point(
 3759                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3760                        Bias::Left,
 3761                    );
 3762
 3763                    if line_start < original_range.start {
 3764                        head = line_start
 3765                    } else {
 3766                        head = next_line_start
 3767                    }
 3768
 3769                    if head <= original_range.start {
 3770                        tail = original_range.end;
 3771                    } else {
 3772                        tail = original_range.start;
 3773                    }
 3774                }
 3775                SelectMode::All => {
 3776                    return;
 3777                }
 3778            };
 3779
 3780            if head < tail {
 3781                pending.start = buffer.anchor_before(head);
 3782                pending.end = buffer.anchor_before(tail);
 3783                pending.reversed = true;
 3784            } else {
 3785                pending.start = buffer.anchor_before(tail);
 3786                pending.end = buffer.anchor_before(head);
 3787                pending.reversed = false;
 3788            }
 3789
 3790            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3791                s.set_pending(pending.clone(), mode);
 3792            });
 3793        } else {
 3794            log::error!("update_selection dispatched with no pending selection");
 3795            return;
 3796        }
 3797
 3798        self.apply_scroll_delta(scroll_delta, window, cx);
 3799        cx.notify();
 3800    }
 3801
 3802    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3803        self.columnar_selection_state.take();
 3804        if let Some(pending_mode) = self.selections.pending_mode() {
 3805            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3806            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3807                s.select(selections);
 3808                s.clear_pending();
 3809                if s.is_extending() {
 3810                    s.set_is_extending(false);
 3811                } else {
 3812                    s.set_select_mode(pending_mode);
 3813                }
 3814            });
 3815        }
 3816    }
 3817
 3818    fn select_columns(
 3819        &mut self,
 3820        head: DisplayPoint,
 3821        goal_column: u32,
 3822        display_map: &DisplaySnapshot,
 3823        window: &mut Window,
 3824        cx: &mut Context<Self>,
 3825    ) {
 3826        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3827            return;
 3828        };
 3829
 3830        let tail = match columnar_state {
 3831            ColumnarSelectionState::FromMouse {
 3832                selection_tail,
 3833                display_point,
 3834            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3835            ColumnarSelectionState::FromSelection { selection_tail } => {
 3836                selection_tail.to_display_point(display_map)
 3837            }
 3838        };
 3839
 3840        let start_row = cmp::min(tail.row(), head.row());
 3841        let end_row = cmp::max(tail.row(), head.row());
 3842        let start_column = cmp::min(tail.column(), goal_column);
 3843        let end_column = cmp::max(tail.column(), goal_column);
 3844        let reversed = start_column < tail.column();
 3845
 3846        let selection_ranges = (start_row.0..=end_row.0)
 3847            .map(DisplayRow)
 3848            .filter_map(|row| {
 3849                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3850                    || start_column <= display_map.line_len(row))
 3851                    && !display_map.is_block_line(row)
 3852                {
 3853                    let start = display_map
 3854                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3855                        .to_point(display_map);
 3856                    let end = display_map
 3857                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3858                        .to_point(display_map);
 3859                    if reversed {
 3860                        Some(end..start)
 3861                    } else {
 3862                        Some(start..end)
 3863                    }
 3864                } else {
 3865                    None
 3866                }
 3867            })
 3868            .collect::<Vec<_>>();
 3869        if selection_ranges.is_empty() {
 3870            return;
 3871        }
 3872
 3873        let ranges = match columnar_state {
 3874            ColumnarSelectionState::FromMouse { .. } => {
 3875                let mut non_empty_ranges = selection_ranges
 3876                    .iter()
 3877                    .filter(|selection_range| selection_range.start != selection_range.end)
 3878                    .peekable();
 3879                if non_empty_ranges.peek().is_some() {
 3880                    non_empty_ranges.cloned().collect()
 3881                } else {
 3882                    selection_ranges
 3883                }
 3884            }
 3885            _ => selection_ranges,
 3886        };
 3887
 3888        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3889            s.select_ranges(ranges);
 3890        });
 3891        cx.notify();
 3892    }
 3893
 3894    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3895        self.selections
 3896            .all_adjusted(snapshot)
 3897            .iter()
 3898            .any(|selection| !selection.is_empty())
 3899    }
 3900
 3901    pub fn has_pending_nonempty_selection(&self) -> bool {
 3902        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3903            Some(Selection { start, end, .. }) => start != end,
 3904            None => false,
 3905        };
 3906
 3907        pending_nonempty_selection
 3908            || (self.columnar_selection_state.is_some()
 3909                && self.selections.disjoint_anchors().len() > 1)
 3910    }
 3911
 3912    pub fn has_pending_selection(&self) -> bool {
 3913        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3914    }
 3915
 3916    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3917        self.selection_mark_mode = false;
 3918        self.selection_drag_state = SelectionDragState::None;
 3919
 3920        if self.clear_expanded_diff_hunks(cx) {
 3921            cx.notify();
 3922            return;
 3923        }
 3924        if self.dismiss_menus_and_popups(true, window, cx) {
 3925            return;
 3926        }
 3927
 3928        if self.mode.is_full()
 3929            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3930        {
 3931            return;
 3932        }
 3933
 3934        cx.propagate();
 3935    }
 3936
 3937    pub fn dismiss_menus_and_popups(
 3938        &mut self,
 3939        is_user_requested: bool,
 3940        window: &mut Window,
 3941        cx: &mut Context<Self>,
 3942    ) -> bool {
 3943        if self.take_rename(false, window, cx).is_some() {
 3944            return true;
 3945        }
 3946
 3947        if self.hide_blame_popover(true, cx) {
 3948            return true;
 3949        }
 3950
 3951        if hide_hover(self, cx) {
 3952            return true;
 3953        }
 3954
 3955        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3956            return true;
 3957        }
 3958
 3959        if self.hide_context_menu(window, cx).is_some() {
 3960            return true;
 3961        }
 3962
 3963        if self.mouse_context_menu.take().is_some() {
 3964            return true;
 3965        }
 3966
 3967        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3968            return true;
 3969        }
 3970
 3971        if self.snippet_stack.pop().is_some() {
 3972            return true;
 3973        }
 3974
 3975        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3976            self.dismiss_diagnostics(cx);
 3977            return true;
 3978        }
 3979
 3980        false
 3981    }
 3982
 3983    fn linked_editing_ranges_for(
 3984        &self,
 3985        selection: Range<text::Anchor>,
 3986        cx: &App,
 3987    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3988        if self.linked_edit_ranges.is_empty() {
 3989            return None;
 3990        }
 3991        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3992            selection.end.buffer_id.and_then(|end_buffer_id| {
 3993                if selection.start.buffer_id != Some(end_buffer_id) {
 3994                    return None;
 3995                }
 3996                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3997                let snapshot = buffer.read(cx).snapshot();
 3998                self.linked_edit_ranges
 3999                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4000                    .map(|ranges| (ranges, snapshot, buffer))
 4001            })?;
 4002        use text::ToOffset as TO;
 4003        // find offset from the start of current range to current cursor position
 4004        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4005
 4006        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4007        let start_difference = start_offset - start_byte_offset;
 4008        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4009        let end_difference = end_offset - start_byte_offset;
 4010        // Current range has associated linked ranges.
 4011        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4012        for range in linked_ranges.iter() {
 4013            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4014            let end_offset = start_offset + end_difference;
 4015            let start_offset = start_offset + start_difference;
 4016            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4017                continue;
 4018            }
 4019            if self.selections.disjoint_anchor_ranges().any(|s| {
 4020                if s.start.buffer_id != selection.start.buffer_id
 4021                    || s.end.buffer_id != selection.end.buffer_id
 4022                {
 4023                    return false;
 4024                }
 4025                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4026                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4027            }) {
 4028                continue;
 4029            }
 4030            let start = buffer_snapshot.anchor_after(start_offset);
 4031            let end = buffer_snapshot.anchor_after(end_offset);
 4032            linked_edits
 4033                .entry(buffer.clone())
 4034                .or_default()
 4035                .push(start..end);
 4036        }
 4037        Some(linked_edits)
 4038    }
 4039
 4040    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4041        let text: Arc<str> = text.into();
 4042
 4043        if self.read_only(cx) {
 4044            return;
 4045        }
 4046
 4047        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4048
 4049        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4050        let mut bracket_inserted = false;
 4051        let mut edits = Vec::new();
 4052        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4053        let mut new_selections = Vec::with_capacity(selections.len());
 4054        let mut new_autoclose_regions = Vec::new();
 4055        let snapshot = self.buffer.read(cx).read(cx);
 4056        let mut clear_linked_edit_ranges = false;
 4057
 4058        for (selection, autoclose_region) in
 4059            self.selections_with_autoclose_regions(selections, &snapshot)
 4060        {
 4061            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4062                // Determine if the inserted text matches the opening or closing
 4063                // bracket of any of this language's bracket pairs.
 4064                let mut bracket_pair = None;
 4065                let mut is_bracket_pair_start = false;
 4066                let mut is_bracket_pair_end = false;
 4067                if !text.is_empty() {
 4068                    let mut bracket_pair_matching_end = None;
 4069                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4070                    //  and they are removing the character that triggered IME popup.
 4071                    for (pair, enabled) in scope.brackets() {
 4072                        if !pair.close && !pair.surround {
 4073                            continue;
 4074                        }
 4075
 4076                        if enabled && pair.start.ends_with(text.as_ref()) {
 4077                            let prefix_len = pair.start.len() - text.len();
 4078                            let preceding_text_matches_prefix = prefix_len == 0
 4079                                || (selection.start.column >= (prefix_len as u32)
 4080                                    && snapshot.contains_str_at(
 4081                                        Point::new(
 4082                                            selection.start.row,
 4083                                            selection.start.column - (prefix_len as u32),
 4084                                        ),
 4085                                        &pair.start[..prefix_len],
 4086                                    ));
 4087                            if preceding_text_matches_prefix {
 4088                                bracket_pair = Some(pair.clone());
 4089                                is_bracket_pair_start = true;
 4090                                break;
 4091                            }
 4092                        }
 4093                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4094                        {
 4095                            // take first bracket pair matching end, but don't break in case a later bracket
 4096                            // pair matches start
 4097                            bracket_pair_matching_end = Some(pair.clone());
 4098                        }
 4099                    }
 4100                    if let Some(end) = bracket_pair_matching_end
 4101                        && bracket_pair.is_none()
 4102                    {
 4103                        bracket_pair = Some(end);
 4104                        is_bracket_pair_end = true;
 4105                    }
 4106                }
 4107
 4108                if let Some(bracket_pair) = bracket_pair {
 4109                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4110                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4111                    let auto_surround =
 4112                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4113                    if selection.is_empty() {
 4114                        if is_bracket_pair_start {
 4115                            // If the inserted text is a suffix of an opening bracket and the
 4116                            // selection is preceded by the rest of the opening bracket, then
 4117                            // insert the closing bracket.
 4118                            let following_text_allows_autoclose = snapshot
 4119                                .chars_at(selection.start)
 4120                                .next()
 4121                                .is_none_or(|c| scope.should_autoclose_before(c));
 4122
 4123                            let preceding_text_allows_autoclose = selection.start.column == 0
 4124                                || snapshot
 4125                                    .reversed_chars_at(selection.start)
 4126                                    .next()
 4127                                    .is_none_or(|c| {
 4128                                        bracket_pair.start != bracket_pair.end
 4129                                            || !snapshot
 4130                                                .char_classifier_at(selection.start)
 4131                                                .is_word(c)
 4132                                    });
 4133
 4134                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4135                                && bracket_pair.start.len() == 1
 4136                            {
 4137                                let target = bracket_pair.start.chars().next().unwrap();
 4138                                let current_line_count = snapshot
 4139                                    .reversed_chars_at(selection.start)
 4140                                    .take_while(|&c| c != '\n')
 4141                                    .filter(|&c| c == target)
 4142                                    .count();
 4143                                current_line_count % 2 == 1
 4144                            } else {
 4145                                false
 4146                            };
 4147
 4148                            if autoclose
 4149                                && bracket_pair.close
 4150                                && following_text_allows_autoclose
 4151                                && preceding_text_allows_autoclose
 4152                                && !is_closing_quote
 4153                            {
 4154                                let anchor = snapshot.anchor_before(selection.end);
 4155                                new_selections.push((selection.map(|_| anchor), text.len()));
 4156                                new_autoclose_regions.push((
 4157                                    anchor,
 4158                                    text.len(),
 4159                                    selection.id,
 4160                                    bracket_pair.clone(),
 4161                                ));
 4162                                edits.push((
 4163                                    selection.range(),
 4164                                    format!("{}{}", text, bracket_pair.end).into(),
 4165                                ));
 4166                                bracket_inserted = true;
 4167                                continue;
 4168                            }
 4169                        }
 4170
 4171                        if let Some(region) = autoclose_region {
 4172                            // If the selection is followed by an auto-inserted closing bracket,
 4173                            // then don't insert that closing bracket again; just move the selection
 4174                            // past the closing bracket.
 4175                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4176                                && text.as_ref() == region.pair.end.as_str()
 4177                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4178                            if should_skip {
 4179                                let anchor = snapshot.anchor_after(selection.end);
 4180                                new_selections
 4181                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4182                                continue;
 4183                            }
 4184                        }
 4185
 4186                        let always_treat_brackets_as_autoclosed = snapshot
 4187                            .language_settings_at(selection.start, cx)
 4188                            .always_treat_brackets_as_autoclosed;
 4189                        if always_treat_brackets_as_autoclosed
 4190                            && is_bracket_pair_end
 4191                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4192                        {
 4193                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4194                            // and the inserted text is a closing bracket and the selection is followed
 4195                            // by the closing bracket then move the selection past the closing bracket.
 4196                            let anchor = snapshot.anchor_after(selection.end);
 4197                            new_selections.push((selection.map(|_| anchor), text.len()));
 4198                            continue;
 4199                        }
 4200                    }
 4201                    // If an opening bracket is 1 character long and is typed while
 4202                    // text is selected, then surround that text with the bracket pair.
 4203                    else if auto_surround
 4204                        && bracket_pair.surround
 4205                        && is_bracket_pair_start
 4206                        && bracket_pair.start.chars().count() == 1
 4207                    {
 4208                        edits.push((selection.start..selection.start, text.clone()));
 4209                        edits.push((
 4210                            selection.end..selection.end,
 4211                            bracket_pair.end.as_str().into(),
 4212                        ));
 4213                        bracket_inserted = true;
 4214                        new_selections.push((
 4215                            Selection {
 4216                                id: selection.id,
 4217                                start: snapshot.anchor_after(selection.start),
 4218                                end: snapshot.anchor_before(selection.end),
 4219                                reversed: selection.reversed,
 4220                                goal: selection.goal,
 4221                            },
 4222                            0,
 4223                        ));
 4224                        continue;
 4225                    }
 4226                }
 4227            }
 4228
 4229            if self.auto_replace_emoji_shortcode
 4230                && selection.is_empty()
 4231                && text.as_ref().ends_with(':')
 4232                && let Some(possible_emoji_short_code) =
 4233                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4234                && !possible_emoji_short_code.is_empty()
 4235                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4236            {
 4237                let emoji_shortcode_start = Point::new(
 4238                    selection.start.row,
 4239                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4240                );
 4241
 4242                // Remove shortcode from buffer
 4243                edits.push((
 4244                    emoji_shortcode_start..selection.start,
 4245                    "".to_string().into(),
 4246                ));
 4247                new_selections.push((
 4248                    Selection {
 4249                        id: selection.id,
 4250                        start: snapshot.anchor_after(emoji_shortcode_start),
 4251                        end: snapshot.anchor_before(selection.start),
 4252                        reversed: selection.reversed,
 4253                        goal: selection.goal,
 4254                    },
 4255                    0,
 4256                ));
 4257
 4258                // Insert emoji
 4259                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4260                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4261                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4262
 4263                continue;
 4264            }
 4265
 4266            // If not handling any auto-close operation, then just replace the selected
 4267            // text with the given input and move the selection to the end of the
 4268            // newly inserted text.
 4269            let anchor = snapshot.anchor_after(selection.end);
 4270            if !self.linked_edit_ranges.is_empty() {
 4271                let start_anchor = snapshot.anchor_before(selection.start);
 4272
 4273                let is_word_char = text.chars().next().is_none_or(|char| {
 4274                    let classifier = snapshot
 4275                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4276                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4277                    classifier.is_word(char)
 4278                });
 4279
 4280                if is_word_char {
 4281                    if let Some(ranges) = self
 4282                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4283                    {
 4284                        for (buffer, edits) in ranges {
 4285                            linked_edits
 4286                                .entry(buffer.clone())
 4287                                .or_default()
 4288                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4289                        }
 4290                    }
 4291                } else {
 4292                    clear_linked_edit_ranges = true;
 4293                }
 4294            }
 4295
 4296            new_selections.push((selection.map(|_| anchor), 0));
 4297            edits.push((selection.start..selection.end, text.clone()));
 4298        }
 4299
 4300        drop(snapshot);
 4301
 4302        self.transact(window, cx, |this, window, cx| {
 4303            if clear_linked_edit_ranges {
 4304                this.linked_edit_ranges.clear();
 4305            }
 4306            let initial_buffer_versions =
 4307                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4308
 4309            this.buffer.update(cx, |buffer, cx| {
 4310                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4311            });
 4312            for (buffer, edits) in linked_edits {
 4313                buffer.update(cx, |buffer, cx| {
 4314                    let snapshot = buffer.snapshot();
 4315                    let edits = edits
 4316                        .into_iter()
 4317                        .map(|(range, text)| {
 4318                            use text::ToPoint as TP;
 4319                            let end_point = TP::to_point(&range.end, &snapshot);
 4320                            let start_point = TP::to_point(&range.start, &snapshot);
 4321                            (start_point..end_point, text)
 4322                        })
 4323                        .sorted_by_key(|(range, _)| range.start);
 4324                    buffer.edit(edits, None, cx);
 4325                })
 4326            }
 4327            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4328            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4329            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4330            let new_selections =
 4331                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4332                    .zip(new_selection_deltas)
 4333                    .map(|(selection, delta)| Selection {
 4334                        id: selection.id,
 4335                        start: selection.start + delta,
 4336                        end: selection.end + delta,
 4337                        reversed: selection.reversed,
 4338                        goal: SelectionGoal::None,
 4339                    })
 4340                    .collect::<Vec<_>>();
 4341
 4342            let mut i = 0;
 4343            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4344                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4345                let start = map.buffer_snapshot().anchor_before(position);
 4346                let end = map.buffer_snapshot().anchor_after(position);
 4347                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4348                    match existing_state
 4349                        .range
 4350                        .start
 4351                        .cmp(&start, map.buffer_snapshot())
 4352                    {
 4353                        Ordering::Less => i += 1,
 4354                        Ordering::Greater => break,
 4355                        Ordering::Equal => {
 4356                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4357                                Ordering::Less => i += 1,
 4358                                Ordering::Equal => break,
 4359                                Ordering::Greater => break,
 4360                            }
 4361                        }
 4362                    }
 4363                }
 4364                this.autoclose_regions.insert(
 4365                    i,
 4366                    AutocloseRegion {
 4367                        selection_id,
 4368                        range: start..end,
 4369                        pair,
 4370                    },
 4371                );
 4372            }
 4373
 4374            let had_active_edit_prediction = this.has_active_edit_prediction();
 4375            this.change_selections(
 4376                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4377                window,
 4378                cx,
 4379                |s| s.select(new_selections),
 4380            );
 4381
 4382            if !bracket_inserted
 4383                && let Some(on_type_format_task) =
 4384                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4385            {
 4386                on_type_format_task.detach_and_log_err(cx);
 4387            }
 4388
 4389            let editor_settings = EditorSettings::get_global(cx);
 4390            if bracket_inserted
 4391                && (editor_settings.auto_signature_help
 4392                    || editor_settings.show_signature_help_after_edits)
 4393            {
 4394                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4395            }
 4396
 4397            let trigger_in_words =
 4398                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4399            if this.hard_wrap.is_some() {
 4400                let latest: Range<Point> = this.selections.newest(&map).range();
 4401                if latest.is_empty()
 4402                    && this
 4403                        .buffer()
 4404                        .read(cx)
 4405                        .snapshot(cx)
 4406                        .line_len(MultiBufferRow(latest.start.row))
 4407                        == latest.start.column
 4408                {
 4409                    this.rewrap_impl(
 4410                        RewrapOptions {
 4411                            override_language_settings: true,
 4412                            preserve_existing_whitespace: true,
 4413                        },
 4414                        cx,
 4415                    )
 4416                }
 4417            }
 4418            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4419            refresh_linked_ranges(this, window, cx);
 4420            this.refresh_edit_prediction(true, false, window, cx);
 4421            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4422        });
 4423    }
 4424
 4425    fn find_possible_emoji_shortcode_at_position(
 4426        snapshot: &MultiBufferSnapshot,
 4427        position: Point,
 4428    ) -> Option<String> {
 4429        let mut chars = Vec::new();
 4430        let mut found_colon = false;
 4431        for char in snapshot.reversed_chars_at(position).take(100) {
 4432            // Found a possible emoji shortcode in the middle of the buffer
 4433            if found_colon {
 4434                if char.is_whitespace() {
 4435                    chars.reverse();
 4436                    return Some(chars.iter().collect());
 4437                }
 4438                // If the previous character is not a whitespace, we are in the middle of a word
 4439                // and we only want to complete the shortcode if the word is made up of other emojis
 4440                let mut containing_word = String::new();
 4441                for ch in snapshot
 4442                    .reversed_chars_at(position)
 4443                    .skip(chars.len() + 1)
 4444                    .take(100)
 4445                {
 4446                    if ch.is_whitespace() {
 4447                        break;
 4448                    }
 4449                    containing_word.push(ch);
 4450                }
 4451                let containing_word = containing_word.chars().rev().collect::<String>();
 4452                if util::word_consists_of_emojis(containing_word.as_str()) {
 4453                    chars.reverse();
 4454                    return Some(chars.iter().collect());
 4455                }
 4456            }
 4457
 4458            if char.is_whitespace() || !char.is_ascii() {
 4459                return None;
 4460            }
 4461            if char == ':' {
 4462                found_colon = true;
 4463            } else {
 4464                chars.push(char);
 4465            }
 4466        }
 4467        // Found a possible emoji shortcode at the beginning of the buffer
 4468        chars.reverse();
 4469        Some(chars.iter().collect())
 4470    }
 4471
 4472    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4473        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4474        self.transact(window, cx, |this, window, cx| {
 4475            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4476                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4477                let multi_buffer = this.buffer.read(cx);
 4478                let buffer = multi_buffer.snapshot(cx);
 4479                selections
 4480                    .iter()
 4481                    .map(|selection| {
 4482                        let start_point = selection.start.to_point(&buffer);
 4483                        let mut existing_indent =
 4484                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4485                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4486                        let start = selection.start;
 4487                        let end = selection.end;
 4488                        let selection_is_empty = start == end;
 4489                        let language_scope = buffer.language_scope_at(start);
 4490                        let (
 4491                            comment_delimiter,
 4492                            doc_delimiter,
 4493                            insert_extra_newline,
 4494                            indent_on_newline,
 4495                            indent_on_extra_newline,
 4496                        ) = if let Some(language) = &language_scope {
 4497                            let mut insert_extra_newline =
 4498                                insert_extra_newline_brackets(&buffer, start..end, language)
 4499                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4500
 4501                            // Comment extension on newline is allowed only for cursor selections
 4502                            let comment_delimiter = maybe!({
 4503                                if !selection_is_empty {
 4504                                    return None;
 4505                                }
 4506
 4507                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4508                                    return None;
 4509                                }
 4510
 4511                                let delimiters = language.line_comment_prefixes();
 4512                                let max_len_of_delimiter =
 4513                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4514                                let (snapshot, range) =
 4515                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4516
 4517                                let num_of_whitespaces = snapshot
 4518                                    .chars_for_range(range.clone())
 4519                                    .take_while(|c| c.is_whitespace())
 4520                                    .count();
 4521                                let comment_candidate = snapshot
 4522                                    .chars_for_range(range.clone())
 4523                                    .skip(num_of_whitespaces)
 4524                                    .take(max_len_of_delimiter)
 4525                                    .collect::<String>();
 4526                                let (delimiter, trimmed_len) = delimiters
 4527                                    .iter()
 4528                                    .filter_map(|delimiter| {
 4529                                        let prefix = delimiter.trim_end();
 4530                                        if comment_candidate.starts_with(prefix) {
 4531                                            Some((delimiter, prefix.len()))
 4532                                        } else {
 4533                                            None
 4534                                        }
 4535                                    })
 4536                                    .max_by_key(|(_, len)| *len)?;
 4537
 4538                                if let Some(BlockCommentConfig {
 4539                                    start: block_start, ..
 4540                                }) = language.block_comment()
 4541                                {
 4542                                    let block_start_trimmed = block_start.trim_end();
 4543                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4544                                        let line_content = snapshot
 4545                                            .chars_for_range(range)
 4546                                            .skip(num_of_whitespaces)
 4547                                            .take(block_start_trimmed.len())
 4548                                            .collect::<String>();
 4549
 4550                                        if line_content.starts_with(block_start_trimmed) {
 4551                                            return None;
 4552                                        }
 4553                                    }
 4554                                }
 4555
 4556                                let cursor_is_placed_after_comment_marker =
 4557                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4558                                if cursor_is_placed_after_comment_marker {
 4559                                    Some(delimiter.clone())
 4560                                } else {
 4561                                    None
 4562                                }
 4563                            });
 4564
 4565                            let mut indent_on_newline = IndentSize::spaces(0);
 4566                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4567
 4568                            let doc_delimiter = maybe!({
 4569                                if !selection_is_empty {
 4570                                    return None;
 4571                                }
 4572
 4573                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4574                                    return None;
 4575                                }
 4576
 4577                                let BlockCommentConfig {
 4578                                    start: start_tag,
 4579                                    end: end_tag,
 4580                                    prefix: delimiter,
 4581                                    tab_size: len,
 4582                                } = language.documentation_comment()?;
 4583                                let is_within_block_comment = buffer
 4584                                    .language_scope_at(start_point)
 4585                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4586                                if !is_within_block_comment {
 4587                                    return None;
 4588                                }
 4589
 4590                                let (snapshot, range) =
 4591                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4592
 4593                                let num_of_whitespaces = snapshot
 4594                                    .chars_for_range(range.clone())
 4595                                    .take_while(|c| c.is_whitespace())
 4596                                    .count();
 4597
 4598                                // 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.
 4599                                let column = start_point.column;
 4600                                let cursor_is_after_start_tag = {
 4601                                    let start_tag_len = start_tag.len();
 4602                                    let start_tag_line = snapshot
 4603                                        .chars_for_range(range.clone())
 4604                                        .skip(num_of_whitespaces)
 4605                                        .take(start_tag_len)
 4606                                        .collect::<String>();
 4607                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4608                                        num_of_whitespaces + start_tag_len <= column as usize
 4609                                    } else {
 4610                                        false
 4611                                    }
 4612                                };
 4613
 4614                                let cursor_is_after_delimiter = {
 4615                                    let delimiter_trim = delimiter.trim_end();
 4616                                    let delimiter_line = snapshot
 4617                                        .chars_for_range(range.clone())
 4618                                        .skip(num_of_whitespaces)
 4619                                        .take(delimiter_trim.len())
 4620                                        .collect::<String>();
 4621                                    if delimiter_line.starts_with(delimiter_trim) {
 4622                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4623                                    } else {
 4624                                        false
 4625                                    }
 4626                                };
 4627
 4628                                let cursor_is_before_end_tag_if_exists = {
 4629                                    let mut char_position = 0u32;
 4630                                    let mut end_tag_offset = None;
 4631
 4632                                    'outer: for chunk in snapshot.text_for_range(range) {
 4633                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4634                                            let chars_before_match =
 4635                                                chunk[..byte_pos].chars().count() as u32;
 4636                                            end_tag_offset =
 4637                                                Some(char_position + chars_before_match);
 4638                                            break 'outer;
 4639                                        }
 4640                                        char_position += chunk.chars().count() as u32;
 4641                                    }
 4642
 4643                                    if let Some(end_tag_offset) = end_tag_offset {
 4644                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4645                                        if cursor_is_after_start_tag {
 4646                                            if cursor_is_before_end_tag {
 4647                                                insert_extra_newline = true;
 4648                                            }
 4649                                            let cursor_is_at_start_of_end_tag =
 4650                                                column == end_tag_offset;
 4651                                            if cursor_is_at_start_of_end_tag {
 4652                                                indent_on_extra_newline.len = *len;
 4653                                            }
 4654                                        }
 4655                                        cursor_is_before_end_tag
 4656                                    } else {
 4657                                        true
 4658                                    }
 4659                                };
 4660
 4661                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4662                                    && cursor_is_before_end_tag_if_exists
 4663                                {
 4664                                    if cursor_is_after_start_tag {
 4665                                        indent_on_newline.len = *len;
 4666                                    }
 4667                                    Some(delimiter.clone())
 4668                                } else {
 4669                                    None
 4670                                }
 4671                            });
 4672
 4673                            (
 4674                                comment_delimiter,
 4675                                doc_delimiter,
 4676                                insert_extra_newline,
 4677                                indent_on_newline,
 4678                                indent_on_extra_newline,
 4679                            )
 4680                        } else {
 4681                            (
 4682                                None,
 4683                                None,
 4684                                false,
 4685                                IndentSize::default(),
 4686                                IndentSize::default(),
 4687                            )
 4688                        };
 4689
 4690                        let prevent_auto_indent = doc_delimiter.is_some();
 4691                        let delimiter = comment_delimiter.or(doc_delimiter);
 4692
 4693                        let capacity_for_delimiter =
 4694                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4695                        let mut new_text = String::with_capacity(
 4696                            1 + capacity_for_delimiter
 4697                                + existing_indent.len as usize
 4698                                + indent_on_newline.len as usize
 4699                                + indent_on_extra_newline.len as usize,
 4700                        );
 4701                        new_text.push('\n');
 4702                        new_text.extend(existing_indent.chars());
 4703                        new_text.extend(indent_on_newline.chars());
 4704
 4705                        if let Some(delimiter) = &delimiter {
 4706                            new_text.push_str(delimiter);
 4707                        }
 4708
 4709                        if insert_extra_newline {
 4710                            new_text.push('\n');
 4711                            new_text.extend(existing_indent.chars());
 4712                            new_text.extend(indent_on_extra_newline.chars());
 4713                        }
 4714
 4715                        let anchor = buffer.anchor_after(end);
 4716                        let new_selection = selection.map(|_| anchor);
 4717                        (
 4718                            ((start..end, new_text), prevent_auto_indent),
 4719                            (insert_extra_newline, new_selection),
 4720                        )
 4721                    })
 4722                    .unzip()
 4723            };
 4724
 4725            let mut auto_indent_edits = Vec::new();
 4726            let mut edits = Vec::new();
 4727            for (edit, prevent_auto_indent) in edits_with_flags {
 4728                if prevent_auto_indent {
 4729                    edits.push(edit);
 4730                } else {
 4731                    auto_indent_edits.push(edit);
 4732                }
 4733            }
 4734            if !edits.is_empty() {
 4735                this.edit(edits, cx);
 4736            }
 4737            if !auto_indent_edits.is_empty() {
 4738                this.edit_with_autoindent(auto_indent_edits, cx);
 4739            }
 4740
 4741            let buffer = this.buffer.read(cx).snapshot(cx);
 4742            let new_selections = selection_info
 4743                .into_iter()
 4744                .map(|(extra_newline_inserted, new_selection)| {
 4745                    let mut cursor = new_selection.end.to_point(&buffer);
 4746                    if extra_newline_inserted {
 4747                        cursor.row -= 1;
 4748                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4749                    }
 4750                    new_selection.map(|_| cursor)
 4751                })
 4752                .collect();
 4753
 4754            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4755            this.refresh_edit_prediction(true, false, window, cx);
 4756        });
 4757    }
 4758
 4759    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4761
 4762        let buffer = self.buffer.read(cx);
 4763        let snapshot = buffer.snapshot(cx);
 4764
 4765        let mut edits = Vec::new();
 4766        let mut rows = Vec::new();
 4767
 4768        for (rows_inserted, selection) in self
 4769            .selections
 4770            .all_adjusted(&self.display_snapshot(cx))
 4771            .into_iter()
 4772            .enumerate()
 4773        {
 4774            let cursor = selection.head();
 4775            let row = cursor.row;
 4776
 4777            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4778
 4779            let newline = "\n".to_string();
 4780            edits.push((start_of_line..start_of_line, newline));
 4781
 4782            rows.push(row + rows_inserted as u32);
 4783        }
 4784
 4785        self.transact(window, cx, |editor, window, cx| {
 4786            editor.edit(edits, cx);
 4787
 4788            editor.change_selections(Default::default(), window, cx, |s| {
 4789                let mut index = 0;
 4790                s.move_cursors_with(|map, _, _| {
 4791                    let row = rows[index];
 4792                    index += 1;
 4793
 4794                    let point = Point::new(row, 0);
 4795                    let boundary = map.next_line_boundary(point).1;
 4796                    let clipped = map.clip_point(boundary, Bias::Left);
 4797
 4798                    (clipped, SelectionGoal::None)
 4799                });
 4800            });
 4801
 4802            let mut indent_edits = Vec::new();
 4803            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4804            for row in rows {
 4805                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4806                for (row, indent) in indents {
 4807                    if indent.len == 0 {
 4808                        continue;
 4809                    }
 4810
 4811                    let text = match indent.kind {
 4812                        IndentKind::Space => " ".repeat(indent.len as usize),
 4813                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4814                    };
 4815                    let point = Point::new(row.0, 0);
 4816                    indent_edits.push((point..point, text));
 4817                }
 4818            }
 4819            editor.edit(indent_edits, cx);
 4820        });
 4821    }
 4822
 4823    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4824        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4825
 4826        let buffer = self.buffer.read(cx);
 4827        let snapshot = buffer.snapshot(cx);
 4828
 4829        let mut edits = Vec::new();
 4830        let mut rows = Vec::new();
 4831        let mut rows_inserted = 0;
 4832
 4833        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4834            let cursor = selection.head();
 4835            let row = cursor.row;
 4836
 4837            let point = Point::new(row + 1, 0);
 4838            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4839
 4840            let newline = "\n".to_string();
 4841            edits.push((start_of_line..start_of_line, newline));
 4842
 4843            rows_inserted += 1;
 4844            rows.push(row + rows_inserted);
 4845        }
 4846
 4847        self.transact(window, cx, |editor, window, cx| {
 4848            editor.edit(edits, cx);
 4849
 4850            editor.change_selections(Default::default(), window, cx, |s| {
 4851                let mut index = 0;
 4852                s.move_cursors_with(|map, _, _| {
 4853                    let row = rows[index];
 4854                    index += 1;
 4855
 4856                    let point = Point::new(row, 0);
 4857                    let boundary = map.next_line_boundary(point).1;
 4858                    let clipped = map.clip_point(boundary, Bias::Left);
 4859
 4860                    (clipped, SelectionGoal::None)
 4861                });
 4862            });
 4863
 4864            let mut indent_edits = Vec::new();
 4865            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4866            for row in rows {
 4867                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4868                for (row, indent) in indents {
 4869                    if indent.len == 0 {
 4870                        continue;
 4871                    }
 4872
 4873                    let text = match indent.kind {
 4874                        IndentKind::Space => " ".repeat(indent.len as usize),
 4875                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4876                    };
 4877                    let point = Point::new(row.0, 0);
 4878                    indent_edits.push((point..point, text));
 4879                }
 4880            }
 4881            editor.edit(indent_edits, cx);
 4882        });
 4883    }
 4884
 4885    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4886        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4887            original_indent_columns: Vec::new(),
 4888        });
 4889        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4890    }
 4891
 4892    fn insert_with_autoindent_mode(
 4893        &mut self,
 4894        text: &str,
 4895        autoindent_mode: Option<AutoindentMode>,
 4896        window: &mut Window,
 4897        cx: &mut Context<Self>,
 4898    ) {
 4899        if self.read_only(cx) {
 4900            return;
 4901        }
 4902
 4903        let text: Arc<str> = text.into();
 4904        self.transact(window, cx, |this, window, cx| {
 4905            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4906            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4907                let anchors = {
 4908                    let snapshot = buffer.read(cx);
 4909                    old_selections
 4910                        .iter()
 4911                        .map(|s| {
 4912                            let anchor = snapshot.anchor_after(s.head());
 4913                            s.map(|_| anchor)
 4914                        })
 4915                        .collect::<Vec<_>>()
 4916                };
 4917                buffer.edit(
 4918                    old_selections
 4919                        .iter()
 4920                        .map(|s| (s.start..s.end, text.clone())),
 4921                    autoindent_mode,
 4922                    cx,
 4923                );
 4924                anchors
 4925            });
 4926
 4927            this.change_selections(Default::default(), window, cx, |s| {
 4928                s.select_anchors(selection_anchors);
 4929            });
 4930
 4931            cx.notify();
 4932        });
 4933    }
 4934
 4935    fn trigger_completion_on_input(
 4936        &mut self,
 4937        text: &str,
 4938        trigger_in_words: bool,
 4939        window: &mut Window,
 4940        cx: &mut Context<Self>,
 4941    ) {
 4942        let completions_source = self
 4943            .context_menu
 4944            .borrow()
 4945            .as_ref()
 4946            .and_then(|menu| match menu {
 4947                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4948                CodeContextMenu::CodeActions(_) => None,
 4949            });
 4950
 4951        match completions_source {
 4952            Some(CompletionsMenuSource::Words { .. }) => {
 4953                self.open_or_update_completions_menu(
 4954                    Some(CompletionsMenuSource::Words {
 4955                        ignore_threshold: false,
 4956                    }),
 4957                    None,
 4958                    window,
 4959                    cx,
 4960                );
 4961            }
 4962            Some(CompletionsMenuSource::Normal)
 4963            | Some(CompletionsMenuSource::SnippetChoices)
 4964            | None
 4965                if self.is_completion_trigger(
 4966                    text,
 4967                    trigger_in_words,
 4968                    completions_source.is_some(),
 4969                    cx,
 4970                ) =>
 4971            {
 4972                self.show_completions(
 4973                    &ShowCompletions {
 4974                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4975                    },
 4976                    window,
 4977                    cx,
 4978                )
 4979            }
 4980            _ => {
 4981                self.hide_context_menu(window, cx);
 4982            }
 4983        }
 4984    }
 4985
 4986    fn is_completion_trigger(
 4987        &self,
 4988        text: &str,
 4989        trigger_in_words: bool,
 4990        menu_is_open: bool,
 4991        cx: &mut Context<Self>,
 4992    ) -> bool {
 4993        let position = self.selections.newest_anchor().head();
 4994        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4995            return false;
 4996        };
 4997
 4998        if let Some(completion_provider) = &self.completion_provider {
 4999            completion_provider.is_completion_trigger(
 5000                &buffer,
 5001                position.text_anchor,
 5002                text,
 5003                trigger_in_words,
 5004                menu_is_open,
 5005                cx,
 5006            )
 5007        } else {
 5008            false
 5009        }
 5010    }
 5011
 5012    /// If any empty selections is touching the start of its innermost containing autoclose
 5013    /// region, expand it to select the brackets.
 5014    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5015        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5016        let buffer = self.buffer.read(cx).read(cx);
 5017        let new_selections = self
 5018            .selections_with_autoclose_regions(selections, &buffer)
 5019            .map(|(mut selection, region)| {
 5020                if !selection.is_empty() {
 5021                    return selection;
 5022                }
 5023
 5024                if let Some(region) = region {
 5025                    let mut range = region.range.to_offset(&buffer);
 5026                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5027                        range.start -= region.pair.start.len();
 5028                        if buffer.contains_str_at(range.start, &region.pair.start)
 5029                            && buffer.contains_str_at(range.end, &region.pair.end)
 5030                        {
 5031                            range.end += region.pair.end.len();
 5032                            selection.start = range.start;
 5033                            selection.end = range.end;
 5034
 5035                            return selection;
 5036                        }
 5037                    }
 5038                }
 5039
 5040                let always_treat_brackets_as_autoclosed = buffer
 5041                    .language_settings_at(selection.start, cx)
 5042                    .always_treat_brackets_as_autoclosed;
 5043
 5044                if !always_treat_brackets_as_autoclosed {
 5045                    return selection;
 5046                }
 5047
 5048                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5049                    for (pair, enabled) in scope.brackets() {
 5050                        if !enabled || !pair.close {
 5051                            continue;
 5052                        }
 5053
 5054                        if buffer.contains_str_at(selection.start, &pair.end) {
 5055                            let pair_start_len = pair.start.len();
 5056                            if buffer.contains_str_at(
 5057                                selection.start.saturating_sub(pair_start_len),
 5058                                &pair.start,
 5059                            ) {
 5060                                selection.start -= pair_start_len;
 5061                                selection.end += pair.end.len();
 5062
 5063                                return selection;
 5064                            }
 5065                        }
 5066                    }
 5067                }
 5068
 5069                selection
 5070            })
 5071            .collect();
 5072
 5073        drop(buffer);
 5074        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5075            selections.select(new_selections)
 5076        });
 5077    }
 5078
 5079    /// Iterate the given selections, and for each one, find the smallest surrounding
 5080    /// autoclose region. This uses the ordering of the selections and the autoclose
 5081    /// regions to avoid repeated comparisons.
 5082    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5083        &'a self,
 5084        selections: impl IntoIterator<Item = Selection<D>>,
 5085        buffer: &'a MultiBufferSnapshot,
 5086    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5087        let mut i = 0;
 5088        let mut regions = self.autoclose_regions.as_slice();
 5089        selections.into_iter().map(move |selection| {
 5090            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5091
 5092            let mut enclosing = None;
 5093            while let Some(pair_state) = regions.get(i) {
 5094                if pair_state.range.end.to_offset(buffer) < range.start {
 5095                    regions = &regions[i + 1..];
 5096                    i = 0;
 5097                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5098                    break;
 5099                } else {
 5100                    if pair_state.selection_id == selection.id {
 5101                        enclosing = Some(pair_state);
 5102                    }
 5103                    i += 1;
 5104                }
 5105            }
 5106
 5107            (selection, enclosing)
 5108        })
 5109    }
 5110
 5111    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5112    fn invalidate_autoclose_regions(
 5113        &mut self,
 5114        mut selections: &[Selection<Anchor>],
 5115        buffer: &MultiBufferSnapshot,
 5116    ) {
 5117        self.autoclose_regions.retain(|state| {
 5118            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5119                return false;
 5120            }
 5121
 5122            let mut i = 0;
 5123            while let Some(selection) = selections.get(i) {
 5124                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5125                    selections = &selections[1..];
 5126                    continue;
 5127                }
 5128                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5129                    break;
 5130                }
 5131                if selection.id == state.selection_id {
 5132                    return true;
 5133                } else {
 5134                    i += 1;
 5135                }
 5136            }
 5137            false
 5138        });
 5139    }
 5140
 5141    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5142        let offset = position.to_offset(buffer);
 5143        let (word_range, kind) =
 5144            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5145        if offset > word_range.start && kind == Some(CharKind::Word) {
 5146            Some(
 5147                buffer
 5148                    .text_for_range(word_range.start..offset)
 5149                    .collect::<String>(),
 5150            )
 5151        } else {
 5152            None
 5153        }
 5154    }
 5155
 5156    pub fn visible_excerpts(
 5157        &self,
 5158        cx: &mut Context<Editor>,
 5159    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5160        let Some(project) = self.project() else {
 5161            return HashMap::default();
 5162        };
 5163        let project = project.read(cx);
 5164        let multi_buffer = self.buffer().read(cx);
 5165        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5166        let multi_buffer_visible_start = self
 5167            .scroll_manager
 5168            .anchor()
 5169            .anchor
 5170            .to_point(&multi_buffer_snapshot);
 5171        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5172            multi_buffer_visible_start
 5173                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5174            Bias::Left,
 5175        );
 5176        multi_buffer_snapshot
 5177            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5178            .into_iter()
 5179            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5180            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5181                let buffer_file = project::File::from_dyn(buffer.file())?;
 5182                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5183                let worktree_entry = buffer_worktree
 5184                    .read(cx)
 5185                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5186                if worktree_entry.is_ignored {
 5187                    None
 5188                } else {
 5189                    Some((
 5190                        excerpt_id,
 5191                        (
 5192                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5193                            buffer.version().clone(),
 5194                            excerpt_visible_range,
 5195                        ),
 5196                    ))
 5197                }
 5198            })
 5199            .collect()
 5200    }
 5201
 5202    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5203        TextLayoutDetails {
 5204            text_system: window.text_system().clone(),
 5205            editor_style: self.style.clone().unwrap(),
 5206            rem_size: window.rem_size(),
 5207            scroll_anchor: self.scroll_manager.anchor(),
 5208            visible_rows: self.visible_line_count(),
 5209            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5210        }
 5211    }
 5212
 5213    fn trigger_on_type_formatting(
 5214        &self,
 5215        input: String,
 5216        window: &mut Window,
 5217        cx: &mut Context<Self>,
 5218    ) -> Option<Task<Result<()>>> {
 5219        if input.len() != 1 {
 5220            return None;
 5221        }
 5222
 5223        let project = self.project()?;
 5224        let position = self.selections.newest_anchor().head();
 5225        let (buffer, buffer_position) = self
 5226            .buffer
 5227            .read(cx)
 5228            .text_anchor_for_position(position, cx)?;
 5229
 5230        let settings = language_settings::language_settings(
 5231            buffer
 5232                .read(cx)
 5233                .language_at(buffer_position)
 5234                .map(|l| l.name()),
 5235            buffer.read(cx).file(),
 5236            cx,
 5237        );
 5238        if !settings.use_on_type_format {
 5239            return None;
 5240        }
 5241
 5242        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5243        // hence we do LSP request & edit on host side only — add formats to host's history.
 5244        let push_to_lsp_host_history = true;
 5245        // If this is not the host, append its history with new edits.
 5246        let push_to_client_history = project.read(cx).is_via_collab();
 5247
 5248        let on_type_formatting = project.update(cx, |project, cx| {
 5249            project.on_type_format(
 5250                buffer.clone(),
 5251                buffer_position,
 5252                input,
 5253                push_to_lsp_host_history,
 5254                cx,
 5255            )
 5256        });
 5257        Some(cx.spawn_in(window, async move |editor, cx| {
 5258            if let Some(transaction) = on_type_formatting.await? {
 5259                if push_to_client_history {
 5260                    buffer
 5261                        .update(cx, |buffer, _| {
 5262                            buffer.push_transaction(transaction, Instant::now());
 5263                            buffer.finalize_last_transaction();
 5264                        })
 5265                        .ok();
 5266                }
 5267                editor.update(cx, |editor, cx| {
 5268                    editor.refresh_document_highlights(cx);
 5269                })?;
 5270            }
 5271            Ok(())
 5272        }))
 5273    }
 5274
 5275    pub fn show_word_completions(
 5276        &mut self,
 5277        _: &ShowWordCompletions,
 5278        window: &mut Window,
 5279        cx: &mut Context<Self>,
 5280    ) {
 5281        self.open_or_update_completions_menu(
 5282            Some(CompletionsMenuSource::Words {
 5283                ignore_threshold: true,
 5284            }),
 5285            None,
 5286            window,
 5287            cx,
 5288        );
 5289    }
 5290
 5291    pub fn show_completions(
 5292        &mut self,
 5293        options: &ShowCompletions,
 5294        window: &mut Window,
 5295        cx: &mut Context<Self>,
 5296    ) {
 5297        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5298    }
 5299
 5300    fn open_or_update_completions_menu(
 5301        &mut self,
 5302        requested_source: Option<CompletionsMenuSource>,
 5303        trigger: Option<&str>,
 5304        window: &mut Window,
 5305        cx: &mut Context<Self>,
 5306    ) {
 5307        if self.pending_rename.is_some() {
 5308            return;
 5309        }
 5310
 5311        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5312
 5313        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5314        // inserted and selected. To handle that case, the start of the selection is used so that
 5315        // the menu starts with all choices.
 5316        let position = self
 5317            .selections
 5318            .newest_anchor()
 5319            .start
 5320            .bias_right(&multibuffer_snapshot);
 5321        if position.diff_base_anchor.is_some() {
 5322            return;
 5323        }
 5324        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5325        let Some(buffer) = buffer_position
 5326            .buffer_id
 5327            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5328        else {
 5329            return;
 5330        };
 5331        let buffer_snapshot = buffer.read(cx).snapshot();
 5332
 5333        let query: Option<Arc<String>> =
 5334            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5335                .map(|query| query.into());
 5336
 5337        drop(multibuffer_snapshot);
 5338
 5339        // Hide the current completions menu when query is empty. Without this, cached
 5340        // completions from before the trigger char may be reused (#32774).
 5341        if query.is_none() {
 5342            let menu_is_open = matches!(
 5343                self.context_menu.borrow().as_ref(),
 5344                Some(CodeContextMenu::Completions(_))
 5345            );
 5346            if menu_is_open {
 5347                self.hide_context_menu(window, cx);
 5348            }
 5349        }
 5350
 5351        let mut ignore_word_threshold = false;
 5352        let provider = match requested_source {
 5353            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5354            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5355                ignore_word_threshold = ignore_threshold;
 5356                None
 5357            }
 5358            Some(CompletionsMenuSource::SnippetChoices) => {
 5359                log::error!("bug: SnippetChoices requested_source is not handled");
 5360                None
 5361            }
 5362        };
 5363
 5364        let sort_completions = provider
 5365            .as_ref()
 5366            .is_some_and(|provider| provider.sort_completions());
 5367
 5368        let filter_completions = provider
 5369            .as_ref()
 5370            .is_none_or(|provider| provider.filter_completions());
 5371
 5372        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5373            if filter_completions {
 5374                menu.filter(query.clone(), provider.clone(), window, cx);
 5375            }
 5376            // When `is_incomplete` is false, no need to re-query completions when the current query
 5377            // is a suffix of the initial query.
 5378            if !menu.is_incomplete {
 5379                // If the new query is a suffix of the old query (typing more characters) and
 5380                // the previous result was complete, the existing completions can be filtered.
 5381                //
 5382                // Note that this is always true for snippet completions.
 5383                let query_matches = match (&menu.initial_query, &query) {
 5384                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5385                    (None, _) => true,
 5386                    _ => false,
 5387                };
 5388                if query_matches {
 5389                    let position_matches = if menu.initial_position == position {
 5390                        true
 5391                    } else {
 5392                        let snapshot = self.buffer.read(cx).read(cx);
 5393                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5394                    };
 5395                    if position_matches {
 5396                        return;
 5397                    }
 5398                }
 5399            }
 5400        };
 5401
 5402        let trigger_kind = match trigger {
 5403            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5404                CompletionTriggerKind::TRIGGER_CHARACTER
 5405            }
 5406            _ => CompletionTriggerKind::INVOKED,
 5407        };
 5408        let completion_context = CompletionContext {
 5409            trigger_character: trigger.and_then(|trigger| {
 5410                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5411                    Some(String::from(trigger))
 5412                } else {
 5413                    None
 5414                }
 5415            }),
 5416            trigger_kind,
 5417        };
 5418
 5419        let Anchor {
 5420            excerpt_id: buffer_excerpt_id,
 5421            text_anchor: buffer_position,
 5422            ..
 5423        } = buffer_position;
 5424
 5425        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5426            buffer_snapshot.surrounding_word(buffer_position, None)
 5427        {
 5428            let word_to_exclude = buffer_snapshot
 5429                .text_for_range(word_range.clone())
 5430                .collect::<String>();
 5431            (
 5432                buffer_snapshot.anchor_before(word_range.start)
 5433                    ..buffer_snapshot.anchor_after(buffer_position),
 5434                Some(word_to_exclude),
 5435            )
 5436        } else {
 5437            (buffer_position..buffer_position, None)
 5438        };
 5439
 5440        let language = buffer_snapshot
 5441            .language_at(buffer_position)
 5442            .map(|language| language.name());
 5443
 5444        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5445            .completions
 5446            .clone();
 5447
 5448        let show_completion_documentation = buffer_snapshot
 5449            .settings_at(buffer_position, cx)
 5450            .show_completion_documentation;
 5451
 5452        // The document can be large, so stay in reasonable bounds when searching for words,
 5453        // otherwise completion pop-up might be slow to appear.
 5454        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5455        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5456        let min_word_search = buffer_snapshot.clip_point(
 5457            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5458            Bias::Left,
 5459        );
 5460        let max_word_search = buffer_snapshot.clip_point(
 5461            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5462            Bias::Right,
 5463        );
 5464        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5465            ..buffer_snapshot.point_to_offset(max_word_search);
 5466
 5467        let skip_digits = query
 5468            .as_ref()
 5469            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5470
 5471        let omit_word_completions = !self.word_completions_enabled
 5472            || (!ignore_word_threshold
 5473                && match &query {
 5474                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5475                    None => completion_settings.words_min_length != 0,
 5476                });
 5477
 5478        let (mut words, provider_responses) = match &provider {
 5479            Some(provider) => {
 5480                let provider_responses = provider.completions(
 5481                    buffer_excerpt_id,
 5482                    &buffer,
 5483                    buffer_position,
 5484                    completion_context,
 5485                    window,
 5486                    cx,
 5487                );
 5488
 5489                let words = match (omit_word_completions, completion_settings.words) {
 5490                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5491                        Task::ready(BTreeMap::default())
 5492                    }
 5493                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5494                        .background_spawn(async move {
 5495                            buffer_snapshot.words_in_range(WordsQuery {
 5496                                fuzzy_contents: None,
 5497                                range: word_search_range,
 5498                                skip_digits,
 5499                            })
 5500                        }),
 5501                };
 5502
 5503                (words, provider_responses)
 5504            }
 5505            None => {
 5506                let words = if omit_word_completions {
 5507                    Task::ready(BTreeMap::default())
 5508                } else {
 5509                    cx.background_spawn(async move {
 5510                        buffer_snapshot.words_in_range(WordsQuery {
 5511                            fuzzy_contents: None,
 5512                            range: word_search_range,
 5513                            skip_digits,
 5514                        })
 5515                    })
 5516                };
 5517                (words, Task::ready(Ok(Vec::new())))
 5518            }
 5519        };
 5520
 5521        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5522
 5523        let id = post_inc(&mut self.next_completion_id);
 5524        let task = cx.spawn_in(window, async move |editor, cx| {
 5525            let Ok(()) = editor.update(cx, |this, _| {
 5526                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5527            }) else {
 5528                return;
 5529            };
 5530
 5531            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5532            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5533            let mut completions = Vec::new();
 5534            let mut is_incomplete = false;
 5535            let mut display_options: Option<CompletionDisplayOptions> = None;
 5536            if let Some(provider_responses) = provider_responses.await.log_err()
 5537                && !provider_responses.is_empty()
 5538            {
 5539                for response in provider_responses {
 5540                    completions.extend(response.completions);
 5541                    is_incomplete = is_incomplete || response.is_incomplete;
 5542                    match display_options.as_mut() {
 5543                        None => {
 5544                            display_options = Some(response.display_options);
 5545                        }
 5546                        Some(options) => options.merge(&response.display_options),
 5547                    }
 5548                }
 5549                if completion_settings.words == WordsCompletionMode::Fallback {
 5550                    words = Task::ready(BTreeMap::default());
 5551                }
 5552            }
 5553            let display_options = display_options.unwrap_or_default();
 5554
 5555            let mut words = words.await;
 5556            if let Some(word_to_exclude) = &word_to_exclude {
 5557                words.remove(word_to_exclude);
 5558            }
 5559            for lsp_completion in &completions {
 5560                words.remove(&lsp_completion.new_text);
 5561            }
 5562            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5563                replace_range: word_replace_range.clone(),
 5564                new_text: word.clone(),
 5565                label: CodeLabel::plain(word, None),
 5566                icon_path: None,
 5567                documentation: None,
 5568                source: CompletionSource::BufferWord {
 5569                    word_range,
 5570                    resolved: false,
 5571                },
 5572                insert_text_mode: Some(InsertTextMode::AS_IS),
 5573                confirm: None,
 5574            }));
 5575
 5576            let menu = if completions.is_empty() {
 5577                None
 5578            } else {
 5579                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5580                    let languages = editor
 5581                        .workspace
 5582                        .as_ref()
 5583                        .and_then(|(workspace, _)| workspace.upgrade())
 5584                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5585                    let menu = CompletionsMenu::new(
 5586                        id,
 5587                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5588                        sort_completions,
 5589                        show_completion_documentation,
 5590                        position,
 5591                        query.clone(),
 5592                        is_incomplete,
 5593                        buffer.clone(),
 5594                        completions.into(),
 5595                        display_options,
 5596                        snippet_sort_order,
 5597                        languages,
 5598                        language,
 5599                        cx,
 5600                    );
 5601
 5602                    let query = if filter_completions { query } else { None };
 5603                    let matches_task = if let Some(query) = query {
 5604                        menu.do_async_filtering(query, cx)
 5605                    } else {
 5606                        Task::ready(menu.unfiltered_matches())
 5607                    };
 5608                    (menu, matches_task)
 5609                }) else {
 5610                    return;
 5611                };
 5612
 5613                let matches = matches_task.await;
 5614
 5615                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5616                    // Newer menu already set, so exit.
 5617                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5618                        editor.context_menu.borrow().as_ref()
 5619                        && prev_menu.id > id
 5620                    {
 5621                        return;
 5622                    };
 5623
 5624                    // Only valid to take prev_menu because it the new menu is immediately set
 5625                    // below, or the menu is hidden.
 5626                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5627                        editor.context_menu.borrow_mut().take()
 5628                    {
 5629                        let position_matches =
 5630                            if prev_menu.initial_position == menu.initial_position {
 5631                                true
 5632                            } else {
 5633                                let snapshot = editor.buffer.read(cx).read(cx);
 5634                                prev_menu.initial_position.to_offset(&snapshot)
 5635                                    == menu.initial_position.to_offset(&snapshot)
 5636                            };
 5637                        if position_matches {
 5638                            // Preserve markdown cache before `set_filter_results` because it will
 5639                            // try to populate the documentation cache.
 5640                            menu.preserve_markdown_cache(prev_menu);
 5641                        }
 5642                    };
 5643
 5644                    menu.set_filter_results(matches, provider, window, cx);
 5645                }) else {
 5646                    return;
 5647                };
 5648
 5649                menu.visible().then_some(menu)
 5650            };
 5651
 5652            editor
 5653                .update_in(cx, |editor, window, cx| {
 5654                    if editor.focus_handle.is_focused(window)
 5655                        && let Some(menu) = menu
 5656                    {
 5657                        *editor.context_menu.borrow_mut() =
 5658                            Some(CodeContextMenu::Completions(menu));
 5659
 5660                        crate::hover_popover::hide_hover(editor, cx);
 5661                        if editor.show_edit_predictions_in_menu() {
 5662                            editor.update_visible_edit_prediction(window, cx);
 5663                        } else {
 5664                            editor.discard_edit_prediction(false, cx);
 5665                        }
 5666
 5667                        cx.notify();
 5668                        return;
 5669                    }
 5670
 5671                    if editor.completion_tasks.len() <= 1 {
 5672                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5673                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5674                        // If it was already hidden and we don't show edit predictions in the menu,
 5675                        // we should also show the edit prediction when available.
 5676                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5677                            editor.update_visible_edit_prediction(window, cx);
 5678                        }
 5679                    }
 5680                })
 5681                .ok();
 5682        });
 5683
 5684        self.completion_tasks.push((id, task));
 5685    }
 5686
 5687    #[cfg(feature = "test-support")]
 5688    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5689        let menu = self.context_menu.borrow();
 5690        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5691            let completions = menu.completions.borrow();
 5692            Some(completions.to_vec())
 5693        } else {
 5694            None
 5695        }
 5696    }
 5697
 5698    pub fn with_completions_menu_matching_id<R>(
 5699        &self,
 5700        id: CompletionId,
 5701        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5702    ) -> R {
 5703        let mut context_menu = self.context_menu.borrow_mut();
 5704        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5705            return f(None);
 5706        };
 5707        if completions_menu.id != id {
 5708            return f(None);
 5709        }
 5710        f(Some(completions_menu))
 5711    }
 5712
 5713    pub fn confirm_completion(
 5714        &mut self,
 5715        action: &ConfirmCompletion,
 5716        window: &mut Window,
 5717        cx: &mut Context<Self>,
 5718    ) -> Option<Task<Result<()>>> {
 5719        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5720        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5721    }
 5722
 5723    pub fn confirm_completion_insert(
 5724        &mut self,
 5725        _: &ConfirmCompletionInsert,
 5726        window: &mut Window,
 5727        cx: &mut Context<Self>,
 5728    ) -> Option<Task<Result<()>>> {
 5729        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5730        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5731    }
 5732
 5733    pub fn confirm_completion_replace(
 5734        &mut self,
 5735        _: &ConfirmCompletionReplace,
 5736        window: &mut Window,
 5737        cx: &mut Context<Self>,
 5738    ) -> Option<Task<Result<()>>> {
 5739        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5740        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5741    }
 5742
 5743    pub fn compose_completion(
 5744        &mut self,
 5745        action: &ComposeCompletion,
 5746        window: &mut Window,
 5747        cx: &mut Context<Self>,
 5748    ) -> Option<Task<Result<()>>> {
 5749        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5750        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5751    }
 5752
 5753    fn do_completion(
 5754        &mut self,
 5755        item_ix: Option<usize>,
 5756        intent: CompletionIntent,
 5757        window: &mut Window,
 5758        cx: &mut Context<Editor>,
 5759    ) -> Option<Task<Result<()>>> {
 5760        use language::ToOffset as _;
 5761
 5762        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5763        else {
 5764            return None;
 5765        };
 5766
 5767        let candidate_id = {
 5768            let entries = completions_menu.entries.borrow();
 5769            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5770            if self.show_edit_predictions_in_menu() {
 5771                self.discard_edit_prediction(true, cx);
 5772            }
 5773            mat.candidate_id
 5774        };
 5775
 5776        let completion = completions_menu
 5777            .completions
 5778            .borrow()
 5779            .get(candidate_id)?
 5780            .clone();
 5781        cx.stop_propagation();
 5782
 5783        let buffer_handle = completions_menu.buffer.clone();
 5784
 5785        let CompletionEdit {
 5786            new_text,
 5787            snippet,
 5788            replace_range,
 5789        } = process_completion_for_edit(
 5790            &completion,
 5791            intent,
 5792            &buffer_handle,
 5793            &completions_menu.initial_position.text_anchor,
 5794            cx,
 5795        );
 5796
 5797        let buffer = buffer_handle.read(cx);
 5798        let snapshot = self.buffer.read(cx).snapshot(cx);
 5799        let newest_anchor = self.selections.newest_anchor();
 5800        let replace_range_multibuffer = {
 5801            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5802            excerpt.map_range_from_buffer(replace_range.clone())
 5803        };
 5804        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5805            return None;
 5806        }
 5807
 5808        let old_text = buffer
 5809            .text_for_range(replace_range.clone())
 5810            .collect::<String>();
 5811        let lookbehind = newest_anchor
 5812            .start
 5813            .text_anchor
 5814            .to_offset(buffer)
 5815            .saturating_sub(replace_range.start);
 5816        let lookahead = replace_range
 5817            .end
 5818            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5819        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5820        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5821
 5822        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5823        let mut ranges = Vec::new();
 5824        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5825
 5826        for selection in &selections {
 5827            let range = if selection.id == newest_anchor.id {
 5828                replace_range_multibuffer.clone()
 5829            } else {
 5830                let mut range = selection.range();
 5831
 5832                // if prefix is present, don't duplicate it
 5833                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5834                    range.start = range.start.saturating_sub(lookbehind);
 5835
 5836                    // if suffix is also present, mimic the newest cursor and replace it
 5837                    if selection.id != newest_anchor.id
 5838                        && snapshot.contains_str_at(range.end, suffix)
 5839                    {
 5840                        range.end += lookahead;
 5841                    }
 5842                }
 5843                range
 5844            };
 5845
 5846            ranges.push(range.clone());
 5847
 5848            if !self.linked_edit_ranges.is_empty() {
 5849                let start_anchor = snapshot.anchor_before(range.start);
 5850                let end_anchor = snapshot.anchor_after(range.end);
 5851                if let Some(ranges) = self
 5852                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5853                {
 5854                    for (buffer, edits) in ranges {
 5855                        linked_edits
 5856                            .entry(buffer.clone())
 5857                            .or_default()
 5858                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5859                    }
 5860                }
 5861            }
 5862        }
 5863
 5864        let common_prefix_len = old_text
 5865            .chars()
 5866            .zip(new_text.chars())
 5867            .take_while(|(a, b)| a == b)
 5868            .map(|(a, _)| a.len_utf8())
 5869            .sum::<usize>();
 5870
 5871        cx.emit(EditorEvent::InputHandled {
 5872            utf16_range_to_replace: None,
 5873            text: new_text[common_prefix_len..].into(),
 5874        });
 5875
 5876        self.transact(window, cx, |editor, window, cx| {
 5877            if let Some(mut snippet) = snippet {
 5878                snippet.text = new_text.to_string();
 5879                editor
 5880                    .insert_snippet(&ranges, snippet, window, cx)
 5881                    .log_err();
 5882            } else {
 5883                editor.buffer.update(cx, |multi_buffer, cx| {
 5884                    let auto_indent = match completion.insert_text_mode {
 5885                        Some(InsertTextMode::AS_IS) => None,
 5886                        _ => editor.autoindent_mode.clone(),
 5887                    };
 5888                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5889                    multi_buffer.edit(edits, auto_indent, cx);
 5890                });
 5891            }
 5892            for (buffer, edits) in linked_edits {
 5893                buffer.update(cx, |buffer, cx| {
 5894                    let snapshot = buffer.snapshot();
 5895                    let edits = edits
 5896                        .into_iter()
 5897                        .map(|(range, text)| {
 5898                            use text::ToPoint as TP;
 5899                            let end_point = TP::to_point(&range.end, &snapshot);
 5900                            let start_point = TP::to_point(&range.start, &snapshot);
 5901                            (start_point..end_point, text)
 5902                        })
 5903                        .sorted_by_key(|(range, _)| range.start);
 5904                    buffer.edit(edits, None, cx);
 5905                })
 5906            }
 5907
 5908            editor.refresh_edit_prediction(true, false, window, cx);
 5909        });
 5910        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 5911
 5912        let show_new_completions_on_confirm = completion
 5913            .confirm
 5914            .as_ref()
 5915            .is_some_and(|confirm| confirm(intent, window, cx));
 5916        if show_new_completions_on_confirm {
 5917            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5918        }
 5919
 5920        let provider = self.completion_provider.as_ref()?;
 5921        drop(completion);
 5922        let apply_edits = provider.apply_additional_edits_for_completion(
 5923            buffer_handle,
 5924            completions_menu.completions.clone(),
 5925            candidate_id,
 5926            true,
 5927            cx,
 5928        );
 5929
 5930        let editor_settings = EditorSettings::get_global(cx);
 5931        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5932            // After the code completion is finished, users often want to know what signatures are needed.
 5933            // so we should automatically call signature_help
 5934            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5935        }
 5936
 5937        Some(cx.foreground_executor().spawn(async move {
 5938            apply_edits.await?;
 5939            Ok(())
 5940        }))
 5941    }
 5942
 5943    pub fn toggle_code_actions(
 5944        &mut self,
 5945        action: &ToggleCodeActions,
 5946        window: &mut Window,
 5947        cx: &mut Context<Self>,
 5948    ) {
 5949        let quick_launch = action.quick_launch;
 5950        let mut context_menu = self.context_menu.borrow_mut();
 5951        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5952            if code_actions.deployed_from == action.deployed_from {
 5953                // Toggle if we're selecting the same one
 5954                *context_menu = None;
 5955                cx.notify();
 5956                return;
 5957            } else {
 5958                // Otherwise, clear it and start a new one
 5959                *context_menu = None;
 5960                cx.notify();
 5961            }
 5962        }
 5963        drop(context_menu);
 5964        let snapshot = self.snapshot(window, cx);
 5965        let deployed_from = action.deployed_from.clone();
 5966        let action = action.clone();
 5967        self.completion_tasks.clear();
 5968        self.discard_edit_prediction(false, cx);
 5969
 5970        let multibuffer_point = match &action.deployed_from {
 5971            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5972                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5973            }
 5974            _ => self
 5975                .selections
 5976                .newest::<Point>(&snapshot.display_snapshot)
 5977                .head(),
 5978        };
 5979        let Some((buffer, buffer_row)) = snapshot
 5980            .buffer_snapshot()
 5981            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5982            .and_then(|(buffer_snapshot, range)| {
 5983                self.buffer()
 5984                    .read(cx)
 5985                    .buffer(buffer_snapshot.remote_id())
 5986                    .map(|buffer| (buffer, range.start.row))
 5987            })
 5988        else {
 5989            return;
 5990        };
 5991        let buffer_id = buffer.read(cx).remote_id();
 5992        let tasks = self
 5993            .tasks
 5994            .get(&(buffer_id, buffer_row))
 5995            .map(|t| Arc::new(t.to_owned()));
 5996
 5997        if !self.focus_handle.is_focused(window) {
 5998            return;
 5999        }
 6000        let project = self.project.clone();
 6001
 6002        let code_actions_task = match deployed_from {
 6003            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6004            _ => self.code_actions(buffer_row, window, cx),
 6005        };
 6006
 6007        let runnable_task = match deployed_from {
 6008            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6009            _ => {
 6010                let mut task_context_task = Task::ready(None);
 6011                if let Some(tasks) = &tasks
 6012                    && let Some(project) = project
 6013                {
 6014                    task_context_task =
 6015                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6016                }
 6017
 6018                cx.spawn_in(window, {
 6019                    let buffer = buffer.clone();
 6020                    async move |editor, cx| {
 6021                        let task_context = task_context_task.await;
 6022
 6023                        let resolved_tasks =
 6024                            tasks
 6025                                .zip(task_context.clone())
 6026                                .map(|(tasks, task_context)| ResolvedTasks {
 6027                                    templates: tasks.resolve(&task_context).collect(),
 6028                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6029                                        multibuffer_point.row,
 6030                                        tasks.column,
 6031                                    )),
 6032                                });
 6033                        let debug_scenarios = editor
 6034                            .update(cx, |editor, cx| {
 6035                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6036                            })?
 6037                            .await;
 6038                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6039                    }
 6040                })
 6041            }
 6042        };
 6043
 6044        cx.spawn_in(window, async move |editor, cx| {
 6045            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6046            let code_actions = code_actions_task.await;
 6047            let spawn_straight_away = quick_launch
 6048                && resolved_tasks
 6049                    .as_ref()
 6050                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6051                && code_actions
 6052                    .as_ref()
 6053                    .is_none_or(|actions| actions.is_empty())
 6054                && debug_scenarios.is_empty();
 6055
 6056            editor.update_in(cx, |editor, window, cx| {
 6057                crate::hover_popover::hide_hover(editor, cx);
 6058                let actions = CodeActionContents::new(
 6059                    resolved_tasks,
 6060                    code_actions,
 6061                    debug_scenarios,
 6062                    task_context.unwrap_or_default(),
 6063                );
 6064
 6065                // Don't show the menu if there are no actions available
 6066                if actions.is_empty() {
 6067                    cx.notify();
 6068                    return Task::ready(Ok(()));
 6069                }
 6070
 6071                *editor.context_menu.borrow_mut() =
 6072                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6073                        buffer,
 6074                        actions,
 6075                        selected_item: Default::default(),
 6076                        scroll_handle: UniformListScrollHandle::default(),
 6077                        deployed_from,
 6078                    }));
 6079                cx.notify();
 6080                if spawn_straight_away
 6081                    && let Some(task) = editor.confirm_code_action(
 6082                        &ConfirmCodeAction { item_ix: Some(0) },
 6083                        window,
 6084                        cx,
 6085                    )
 6086                {
 6087                    return task;
 6088                }
 6089
 6090                Task::ready(Ok(()))
 6091            })
 6092        })
 6093        .detach_and_log_err(cx);
 6094    }
 6095
 6096    fn debug_scenarios(
 6097        &mut self,
 6098        resolved_tasks: &Option<ResolvedTasks>,
 6099        buffer: &Entity<Buffer>,
 6100        cx: &mut App,
 6101    ) -> Task<Vec<task::DebugScenario>> {
 6102        maybe!({
 6103            let project = self.project()?;
 6104            let dap_store = project.read(cx).dap_store();
 6105            let mut scenarios = vec![];
 6106            let resolved_tasks = resolved_tasks.as_ref()?;
 6107            let buffer = buffer.read(cx);
 6108            let language = buffer.language()?;
 6109            let file = buffer.file();
 6110            let debug_adapter = language_settings(language.name().into(), file, cx)
 6111                .debuggers
 6112                .first()
 6113                .map(SharedString::from)
 6114                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6115
 6116            dap_store.update(cx, |dap_store, cx| {
 6117                for (_, task) in &resolved_tasks.templates {
 6118                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6119                        task.original_task().clone(),
 6120                        debug_adapter.clone().into(),
 6121                        task.display_label().to_owned().into(),
 6122                        cx,
 6123                    );
 6124                    scenarios.push(maybe_scenario);
 6125                }
 6126            });
 6127            Some(cx.background_spawn(async move {
 6128                futures::future::join_all(scenarios)
 6129                    .await
 6130                    .into_iter()
 6131                    .flatten()
 6132                    .collect::<Vec<_>>()
 6133            }))
 6134        })
 6135        .unwrap_or_else(|| Task::ready(vec![]))
 6136    }
 6137
 6138    fn code_actions(
 6139        &mut self,
 6140        buffer_row: u32,
 6141        window: &mut Window,
 6142        cx: &mut Context<Self>,
 6143    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6144        let mut task = self.code_actions_task.take();
 6145        cx.spawn_in(window, async move |editor, cx| {
 6146            while let Some(prev_task) = task {
 6147                prev_task.await.log_err();
 6148                task = editor
 6149                    .update(cx, |this, _| this.code_actions_task.take())
 6150                    .ok()?;
 6151            }
 6152
 6153            editor
 6154                .update(cx, |editor, cx| {
 6155                    editor
 6156                        .available_code_actions
 6157                        .clone()
 6158                        .and_then(|(location, code_actions)| {
 6159                            let snapshot = location.buffer.read(cx).snapshot();
 6160                            let point_range = location.range.to_point(&snapshot);
 6161                            let point_range = point_range.start.row..=point_range.end.row;
 6162                            if point_range.contains(&buffer_row) {
 6163                                Some(code_actions)
 6164                            } else {
 6165                                None
 6166                            }
 6167                        })
 6168                })
 6169                .ok()
 6170                .flatten()
 6171        })
 6172    }
 6173
 6174    pub fn confirm_code_action(
 6175        &mut self,
 6176        action: &ConfirmCodeAction,
 6177        window: &mut Window,
 6178        cx: &mut Context<Self>,
 6179    ) -> Option<Task<Result<()>>> {
 6180        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6181
 6182        let actions_menu =
 6183            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6184                menu
 6185            } else {
 6186                return None;
 6187            };
 6188
 6189        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6190        let action = actions_menu.actions.get(action_ix)?;
 6191        let title = action.label();
 6192        let buffer = actions_menu.buffer;
 6193        let workspace = self.workspace()?;
 6194
 6195        match action {
 6196            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6197                workspace.update(cx, |workspace, cx| {
 6198                    workspace.schedule_resolved_task(
 6199                        task_source_kind,
 6200                        resolved_task,
 6201                        false,
 6202                        window,
 6203                        cx,
 6204                    );
 6205
 6206                    Some(Task::ready(Ok(())))
 6207                })
 6208            }
 6209            CodeActionsItem::CodeAction {
 6210                excerpt_id,
 6211                action,
 6212                provider,
 6213            } => {
 6214                let apply_code_action =
 6215                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6216                let workspace = workspace.downgrade();
 6217                Some(cx.spawn_in(window, async move |editor, cx| {
 6218                    let project_transaction = apply_code_action.await?;
 6219                    Self::open_project_transaction(
 6220                        &editor,
 6221                        workspace,
 6222                        project_transaction,
 6223                        title,
 6224                        cx,
 6225                    )
 6226                    .await
 6227                }))
 6228            }
 6229            CodeActionsItem::DebugScenario(scenario) => {
 6230                let context = actions_menu.actions.context;
 6231
 6232                workspace.update(cx, |workspace, cx| {
 6233                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6234                    workspace.start_debug_session(
 6235                        scenario,
 6236                        context,
 6237                        Some(buffer),
 6238                        None,
 6239                        window,
 6240                        cx,
 6241                    );
 6242                });
 6243                Some(Task::ready(Ok(())))
 6244            }
 6245        }
 6246    }
 6247
 6248    pub async fn open_project_transaction(
 6249        editor: &WeakEntity<Editor>,
 6250        workspace: WeakEntity<Workspace>,
 6251        transaction: ProjectTransaction,
 6252        title: String,
 6253        cx: &mut AsyncWindowContext,
 6254    ) -> Result<()> {
 6255        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6256        cx.update(|_, cx| {
 6257            entries.sort_unstable_by_key(|(buffer, _)| {
 6258                buffer.read(cx).file().map(|f| f.path().clone())
 6259            });
 6260        })?;
 6261        if entries.is_empty() {
 6262            return Ok(());
 6263        }
 6264
 6265        // If the project transaction's edits are all contained within this editor, then
 6266        // avoid opening a new editor to display them.
 6267
 6268        if let [(buffer, transaction)] = &*entries {
 6269            let excerpt = editor.update(cx, |editor, cx| {
 6270                editor
 6271                    .buffer()
 6272                    .read(cx)
 6273                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6274            })?;
 6275            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6276                && excerpted_buffer == *buffer
 6277            {
 6278                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6279                    let excerpt_range = excerpt_range.to_offset(buffer);
 6280                    buffer
 6281                        .edited_ranges_for_transaction::<usize>(transaction)
 6282                        .all(|range| {
 6283                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6284                        })
 6285                })?;
 6286
 6287                if all_edits_within_excerpt {
 6288                    return Ok(());
 6289                }
 6290            }
 6291        }
 6292
 6293        let mut ranges_to_highlight = Vec::new();
 6294        let excerpt_buffer = cx.new(|cx| {
 6295            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6296            for (buffer_handle, transaction) in &entries {
 6297                let edited_ranges = buffer_handle
 6298                    .read(cx)
 6299                    .edited_ranges_for_transaction::<Point>(transaction)
 6300                    .collect::<Vec<_>>();
 6301                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6302                    PathKey::for_buffer(buffer_handle, cx),
 6303                    buffer_handle.clone(),
 6304                    edited_ranges,
 6305                    multibuffer_context_lines(cx),
 6306                    cx,
 6307                );
 6308
 6309                ranges_to_highlight.extend(ranges);
 6310            }
 6311            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6312            multibuffer
 6313        })?;
 6314
 6315        workspace.update_in(cx, |workspace, window, cx| {
 6316            let project = workspace.project().clone();
 6317            let editor =
 6318                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6319            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6320            editor.update(cx, |editor, cx| {
 6321                editor.highlight_background::<Self>(
 6322                    &ranges_to_highlight,
 6323                    |theme| theme.colors().editor_highlighted_line_background,
 6324                    cx,
 6325                );
 6326            });
 6327        })?;
 6328
 6329        Ok(())
 6330    }
 6331
 6332    pub fn clear_code_action_providers(&mut self) {
 6333        self.code_action_providers.clear();
 6334        self.available_code_actions.take();
 6335    }
 6336
 6337    pub fn add_code_action_provider(
 6338        &mut self,
 6339        provider: Rc<dyn CodeActionProvider>,
 6340        window: &mut Window,
 6341        cx: &mut Context<Self>,
 6342    ) {
 6343        if self
 6344            .code_action_providers
 6345            .iter()
 6346            .any(|existing_provider| existing_provider.id() == provider.id())
 6347        {
 6348            return;
 6349        }
 6350
 6351        self.code_action_providers.push(provider);
 6352        self.refresh_code_actions(window, cx);
 6353    }
 6354
 6355    pub fn remove_code_action_provider(
 6356        &mut self,
 6357        id: Arc<str>,
 6358        window: &mut Window,
 6359        cx: &mut Context<Self>,
 6360    ) {
 6361        self.code_action_providers
 6362            .retain(|provider| provider.id() != id);
 6363        self.refresh_code_actions(window, cx);
 6364    }
 6365
 6366    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6367        !self.code_action_providers.is_empty()
 6368            && EditorSettings::get_global(cx).toolbar.code_actions
 6369    }
 6370
 6371    pub fn has_available_code_actions(&self) -> bool {
 6372        self.available_code_actions
 6373            .as_ref()
 6374            .is_some_and(|(_, actions)| !actions.is_empty())
 6375    }
 6376
 6377    fn render_inline_code_actions(
 6378        &self,
 6379        icon_size: ui::IconSize,
 6380        display_row: DisplayRow,
 6381        is_active: bool,
 6382        cx: &mut Context<Self>,
 6383    ) -> AnyElement {
 6384        let show_tooltip = !self.context_menu_visible();
 6385        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6386            .icon_size(icon_size)
 6387            .shape(ui::IconButtonShape::Square)
 6388            .icon_color(ui::Color::Hidden)
 6389            .toggle_state(is_active)
 6390            .when(show_tooltip, |this| {
 6391                this.tooltip({
 6392                    let focus_handle = self.focus_handle.clone();
 6393                    move |_window, cx| {
 6394                        Tooltip::for_action_in(
 6395                            "Toggle Code Actions",
 6396                            &ToggleCodeActions {
 6397                                deployed_from: None,
 6398                                quick_launch: false,
 6399                            },
 6400                            &focus_handle,
 6401                            cx,
 6402                        )
 6403                    }
 6404                })
 6405            })
 6406            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6407                window.focus(&editor.focus_handle(cx));
 6408                editor.toggle_code_actions(
 6409                    &crate::actions::ToggleCodeActions {
 6410                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6411                            display_row,
 6412                        )),
 6413                        quick_launch: false,
 6414                    },
 6415                    window,
 6416                    cx,
 6417                );
 6418            }))
 6419            .into_any_element()
 6420    }
 6421
 6422    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6423        &self.context_menu
 6424    }
 6425
 6426    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6427        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6428            cx.background_executor()
 6429                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6430                .await;
 6431
 6432            let (start_buffer, start, _, end, newest_selection) = this
 6433                .update(cx, |this, cx| {
 6434                    let newest_selection = this.selections.newest_anchor().clone();
 6435                    if newest_selection.head().diff_base_anchor.is_some() {
 6436                        return None;
 6437                    }
 6438                    let display_snapshot = this.display_snapshot(cx);
 6439                    let newest_selection_adjusted =
 6440                        this.selections.newest_adjusted(&display_snapshot);
 6441                    let buffer = this.buffer.read(cx);
 6442
 6443                    let (start_buffer, start) =
 6444                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6445                    let (end_buffer, end) =
 6446                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6447
 6448                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6449                })?
 6450                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6451                .context(
 6452                    "Expected selection to lie in a single buffer when refreshing code actions",
 6453                )?;
 6454            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6455                let providers = this.code_action_providers.clone();
 6456                let tasks = this
 6457                    .code_action_providers
 6458                    .iter()
 6459                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6460                    .collect::<Vec<_>>();
 6461                (providers, tasks)
 6462            })?;
 6463
 6464            let mut actions = Vec::new();
 6465            for (provider, provider_actions) in
 6466                providers.into_iter().zip(future::join_all(tasks).await)
 6467            {
 6468                if let Some(provider_actions) = provider_actions.log_err() {
 6469                    actions.extend(provider_actions.into_iter().map(|action| {
 6470                        AvailableCodeAction {
 6471                            excerpt_id: newest_selection.start.excerpt_id,
 6472                            action,
 6473                            provider: provider.clone(),
 6474                        }
 6475                    }));
 6476                }
 6477            }
 6478
 6479            this.update(cx, |this, cx| {
 6480                this.available_code_actions = if actions.is_empty() {
 6481                    None
 6482                } else {
 6483                    Some((
 6484                        Location {
 6485                            buffer: start_buffer,
 6486                            range: start..end,
 6487                        },
 6488                        actions.into(),
 6489                    ))
 6490                };
 6491                cx.notify();
 6492            })
 6493        }));
 6494    }
 6495
 6496    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6497        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6498            self.show_git_blame_inline = false;
 6499
 6500            self.show_git_blame_inline_delay_task =
 6501                Some(cx.spawn_in(window, async move |this, cx| {
 6502                    cx.background_executor().timer(delay).await;
 6503
 6504                    this.update(cx, |this, cx| {
 6505                        this.show_git_blame_inline = true;
 6506                        cx.notify();
 6507                    })
 6508                    .log_err();
 6509                }));
 6510        }
 6511    }
 6512
 6513    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6514        let snapshot = self.snapshot(window, cx);
 6515        let cursor = self
 6516            .selections
 6517            .newest::<Point>(&snapshot.display_snapshot)
 6518            .head();
 6519        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6520        else {
 6521            return;
 6522        };
 6523
 6524        let Some(blame) = self.blame.as_ref() else {
 6525            return;
 6526        };
 6527
 6528        let row_info = RowInfo {
 6529            buffer_id: Some(buffer.remote_id()),
 6530            buffer_row: Some(point.row),
 6531            ..Default::default()
 6532        };
 6533        let Some((buffer, blame_entry)) = blame
 6534            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6535            .flatten()
 6536        else {
 6537            return;
 6538        };
 6539
 6540        let anchor = self.selections.newest_anchor().head();
 6541        let position = self.to_pixel_point(anchor, &snapshot, window);
 6542        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6543            self.show_blame_popover(
 6544                buffer,
 6545                &blame_entry,
 6546                position + last_bounds.origin,
 6547                true,
 6548                cx,
 6549            );
 6550        };
 6551    }
 6552
 6553    fn show_blame_popover(
 6554        &mut self,
 6555        buffer: BufferId,
 6556        blame_entry: &BlameEntry,
 6557        position: gpui::Point<Pixels>,
 6558        ignore_timeout: bool,
 6559        cx: &mut Context<Self>,
 6560    ) {
 6561        if let Some(state) = &mut self.inline_blame_popover {
 6562            state.hide_task.take();
 6563        } else {
 6564            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6565            let blame_entry = blame_entry.clone();
 6566            let show_task = cx.spawn(async move |editor, cx| {
 6567                if !ignore_timeout {
 6568                    cx.background_executor()
 6569                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6570                        .await;
 6571                }
 6572                editor
 6573                    .update(cx, |editor, cx| {
 6574                        editor.inline_blame_popover_show_task.take();
 6575                        let Some(blame) = editor.blame.as_ref() else {
 6576                            return;
 6577                        };
 6578                        let blame = blame.read(cx);
 6579                        let details = blame.details_for_entry(buffer, &blame_entry);
 6580                        let markdown = cx.new(|cx| {
 6581                            Markdown::new(
 6582                                details
 6583                                    .as_ref()
 6584                                    .map(|message| message.message.clone())
 6585                                    .unwrap_or_default(),
 6586                                None,
 6587                                None,
 6588                                cx,
 6589                            )
 6590                        });
 6591                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6592                            position,
 6593                            hide_task: None,
 6594                            popover_bounds: None,
 6595                            popover_state: InlineBlamePopoverState {
 6596                                scroll_handle: ScrollHandle::new(),
 6597                                commit_message: details,
 6598                                markdown,
 6599                            },
 6600                            keyboard_grace: ignore_timeout,
 6601                        });
 6602                        cx.notify();
 6603                    })
 6604                    .ok();
 6605            });
 6606            self.inline_blame_popover_show_task = Some(show_task);
 6607        }
 6608    }
 6609
 6610    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6611        self.inline_blame_popover_show_task.take();
 6612        if let Some(state) = &mut self.inline_blame_popover {
 6613            let hide_task = cx.spawn(async move |editor, cx| {
 6614                if !ignore_timeout {
 6615                    cx.background_executor()
 6616                        .timer(std::time::Duration::from_millis(100))
 6617                        .await;
 6618                }
 6619                editor
 6620                    .update(cx, |editor, cx| {
 6621                        editor.inline_blame_popover.take();
 6622                        cx.notify();
 6623                    })
 6624                    .ok();
 6625            });
 6626            state.hide_task = Some(hide_task);
 6627            true
 6628        } else {
 6629            false
 6630        }
 6631    }
 6632
 6633    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6634        if self.pending_rename.is_some() {
 6635            return None;
 6636        }
 6637
 6638        let provider = self.semantics_provider.clone()?;
 6639        let buffer = self.buffer.read(cx);
 6640        let newest_selection = self.selections.newest_anchor().clone();
 6641        let cursor_position = newest_selection.head();
 6642        let (cursor_buffer, cursor_buffer_position) =
 6643            buffer.text_anchor_for_position(cursor_position, cx)?;
 6644        let (tail_buffer, tail_buffer_position) =
 6645            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6646        if cursor_buffer != tail_buffer {
 6647            return None;
 6648        }
 6649
 6650        let snapshot = cursor_buffer.read(cx).snapshot();
 6651        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6652        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6653        if start_word_range != end_word_range {
 6654            self.document_highlights_task.take();
 6655            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6656            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6657            return None;
 6658        }
 6659
 6660        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6661        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6662            cx.background_executor()
 6663                .timer(Duration::from_millis(debounce))
 6664                .await;
 6665
 6666            let highlights = if let Some(highlights) = cx
 6667                .update(|cx| {
 6668                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6669                })
 6670                .ok()
 6671                .flatten()
 6672            {
 6673                highlights.await.log_err()
 6674            } else {
 6675                None
 6676            };
 6677
 6678            if let Some(highlights) = highlights {
 6679                this.update(cx, |this, cx| {
 6680                    if this.pending_rename.is_some() {
 6681                        return;
 6682                    }
 6683
 6684                    let buffer = this.buffer.read(cx);
 6685                    if buffer
 6686                        .text_anchor_for_position(cursor_position, cx)
 6687                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6688                    {
 6689                        return;
 6690                    }
 6691
 6692                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6693                    let mut write_ranges = Vec::new();
 6694                    let mut read_ranges = Vec::new();
 6695                    for highlight in highlights {
 6696                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6697                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6698                        {
 6699                            let start = highlight
 6700                                .range
 6701                                .start
 6702                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6703                            let end = highlight
 6704                                .range
 6705                                .end
 6706                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6707                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6708                                continue;
 6709                            }
 6710
 6711                            let range =
 6712                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6713                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6714                                write_ranges.push(range);
 6715                            } else {
 6716                                read_ranges.push(range);
 6717                            }
 6718                        }
 6719                    }
 6720
 6721                    this.highlight_background::<DocumentHighlightRead>(
 6722                        &read_ranges,
 6723                        |theme| theme.colors().editor_document_highlight_read_background,
 6724                        cx,
 6725                    );
 6726                    this.highlight_background::<DocumentHighlightWrite>(
 6727                        &write_ranges,
 6728                        |theme| theme.colors().editor_document_highlight_write_background,
 6729                        cx,
 6730                    );
 6731                    cx.notify();
 6732                })
 6733                .log_err();
 6734            }
 6735        }));
 6736        None
 6737    }
 6738
 6739    fn prepare_highlight_query_from_selection(
 6740        &mut self,
 6741        window: &Window,
 6742        cx: &mut Context<Editor>,
 6743    ) -> Option<(String, Range<Anchor>)> {
 6744        if matches!(self.mode, EditorMode::SingleLine) {
 6745            return None;
 6746        }
 6747        if !EditorSettings::get_global(cx).selection_highlight {
 6748            return None;
 6749        }
 6750        if self.selections.count() != 1 || self.selections.line_mode() {
 6751            return None;
 6752        }
 6753        let snapshot = self.snapshot(window, cx);
 6754        let selection = self.selections.newest::<Point>(&snapshot);
 6755        // If the selection spans multiple rows OR it is empty
 6756        if selection.start.row != selection.end.row
 6757            || selection.start.column == selection.end.column
 6758        {
 6759            return None;
 6760        }
 6761        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6762        let query = snapshot
 6763            .buffer_snapshot()
 6764            .text_for_range(selection_anchor_range.clone())
 6765            .collect::<String>();
 6766        if query.trim().is_empty() {
 6767            return None;
 6768        }
 6769        Some((query, selection_anchor_range))
 6770    }
 6771
 6772    fn update_selection_occurrence_highlights(
 6773        &mut self,
 6774        query_text: String,
 6775        query_range: Range<Anchor>,
 6776        multi_buffer_range_to_query: Range<Point>,
 6777        use_debounce: bool,
 6778        window: &mut Window,
 6779        cx: &mut Context<Editor>,
 6780    ) -> Task<()> {
 6781        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6782        cx.spawn_in(window, async move |editor, cx| {
 6783            if use_debounce {
 6784                cx.background_executor()
 6785                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6786                    .await;
 6787            }
 6788            let match_task = cx.background_spawn(async move {
 6789                let buffer_ranges = multi_buffer_snapshot
 6790                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6791                    .into_iter()
 6792                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6793                let mut match_ranges = Vec::new();
 6794                let Ok(regex) = project::search::SearchQuery::text(
 6795                    query_text.clone(),
 6796                    false,
 6797                    false,
 6798                    false,
 6799                    Default::default(),
 6800                    Default::default(),
 6801                    false,
 6802                    None,
 6803                ) else {
 6804                    return Vec::default();
 6805                };
 6806                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6807                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6808                    match_ranges.extend(
 6809                        regex
 6810                            .search(buffer_snapshot, Some(search_range.clone()))
 6811                            .await
 6812                            .into_iter()
 6813                            .filter_map(|match_range| {
 6814                                let match_start = buffer_snapshot
 6815                                    .anchor_after(search_range.start + match_range.start);
 6816                                let match_end = buffer_snapshot
 6817                                    .anchor_before(search_range.start + match_range.end);
 6818                                let match_anchor_range = Anchor::range_in_buffer(
 6819                                    excerpt_id,
 6820                                    buffer_snapshot.remote_id(),
 6821                                    match_start..match_end,
 6822                                );
 6823                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6824                            }),
 6825                    );
 6826                }
 6827                match_ranges
 6828            });
 6829            let match_ranges = match_task.await;
 6830            editor
 6831                .update_in(cx, |editor, _, cx| {
 6832                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6833                    if !match_ranges.is_empty() {
 6834                        editor.highlight_background::<SelectedTextHighlight>(
 6835                            &match_ranges,
 6836                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6837                            cx,
 6838                        )
 6839                    }
 6840                })
 6841                .log_err();
 6842        })
 6843    }
 6844
 6845    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6846        struct NewlineFold;
 6847        let type_id = std::any::TypeId::of::<NewlineFold>();
 6848        if !self.mode.is_single_line() {
 6849            return;
 6850        }
 6851        let snapshot = self.snapshot(window, cx);
 6852        if snapshot.buffer_snapshot().max_point().row == 0 {
 6853            return;
 6854        }
 6855        let task = cx.background_spawn(async move {
 6856            let new_newlines = snapshot
 6857                .buffer_chars_at(0)
 6858                .filter_map(|(c, i)| {
 6859                    if c == '\n' {
 6860                        Some(
 6861                            snapshot.buffer_snapshot().anchor_after(i)
 6862                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6863                        )
 6864                    } else {
 6865                        None
 6866                    }
 6867                })
 6868                .collect::<Vec<_>>();
 6869            let existing_newlines = snapshot
 6870                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6871                .filter_map(|fold| {
 6872                    if fold.placeholder.type_tag == Some(type_id) {
 6873                        Some(fold.range.start..fold.range.end)
 6874                    } else {
 6875                        None
 6876                    }
 6877                })
 6878                .collect::<Vec<_>>();
 6879
 6880            (new_newlines, existing_newlines)
 6881        });
 6882        self.folding_newlines = cx.spawn(async move |this, cx| {
 6883            let (new_newlines, existing_newlines) = task.await;
 6884            if new_newlines == existing_newlines {
 6885                return;
 6886            }
 6887            let placeholder = FoldPlaceholder {
 6888                render: Arc::new(move |_, _, cx| {
 6889                    div()
 6890                        .bg(cx.theme().status().hint_background)
 6891                        .border_b_1()
 6892                        .size_full()
 6893                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6894                        .border_color(cx.theme().status().hint)
 6895                        .child("\\n")
 6896                        .into_any()
 6897                }),
 6898                constrain_width: false,
 6899                merge_adjacent: false,
 6900                type_tag: Some(type_id),
 6901            };
 6902            let creases = new_newlines
 6903                .into_iter()
 6904                .map(|range| Crease::simple(range, placeholder.clone()))
 6905                .collect();
 6906            this.update(cx, |this, cx| {
 6907                this.display_map.update(cx, |display_map, cx| {
 6908                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6909                    display_map.fold(creases, cx);
 6910                });
 6911            })
 6912            .ok();
 6913        });
 6914    }
 6915
 6916    fn refresh_selected_text_highlights(
 6917        &mut self,
 6918        on_buffer_edit: bool,
 6919        window: &mut Window,
 6920        cx: &mut Context<Editor>,
 6921    ) {
 6922        let Some((query_text, query_range)) =
 6923            self.prepare_highlight_query_from_selection(window, cx)
 6924        else {
 6925            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6926            self.quick_selection_highlight_task.take();
 6927            self.debounced_selection_highlight_task.take();
 6928            return;
 6929        };
 6930        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6931        if on_buffer_edit
 6932            || self
 6933                .quick_selection_highlight_task
 6934                .as_ref()
 6935                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6936        {
 6937            let multi_buffer_visible_start = self
 6938                .scroll_manager
 6939                .anchor()
 6940                .anchor
 6941                .to_point(&multi_buffer_snapshot);
 6942            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6943                multi_buffer_visible_start
 6944                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6945                Bias::Left,
 6946            );
 6947            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6948            self.quick_selection_highlight_task = Some((
 6949                query_range.clone(),
 6950                self.update_selection_occurrence_highlights(
 6951                    query_text.clone(),
 6952                    query_range.clone(),
 6953                    multi_buffer_visible_range,
 6954                    false,
 6955                    window,
 6956                    cx,
 6957                ),
 6958            ));
 6959        }
 6960        if on_buffer_edit
 6961            || self
 6962                .debounced_selection_highlight_task
 6963                .as_ref()
 6964                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6965        {
 6966            let multi_buffer_start = multi_buffer_snapshot
 6967                .anchor_before(0)
 6968                .to_point(&multi_buffer_snapshot);
 6969            let multi_buffer_end = multi_buffer_snapshot
 6970                .anchor_after(multi_buffer_snapshot.len())
 6971                .to_point(&multi_buffer_snapshot);
 6972            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6973            self.debounced_selection_highlight_task = Some((
 6974                query_range.clone(),
 6975                self.update_selection_occurrence_highlights(
 6976                    query_text,
 6977                    query_range,
 6978                    multi_buffer_full_range,
 6979                    true,
 6980                    window,
 6981                    cx,
 6982                ),
 6983            ));
 6984        }
 6985    }
 6986
 6987    pub fn refresh_edit_prediction(
 6988        &mut self,
 6989        debounce: bool,
 6990        user_requested: bool,
 6991        window: &mut Window,
 6992        cx: &mut Context<Self>,
 6993    ) -> Option<()> {
 6994        if DisableAiSettings::get_global(cx).disable_ai {
 6995            return None;
 6996        }
 6997
 6998        let provider = self.edit_prediction_provider()?;
 6999        let cursor = self.selections.newest_anchor().head();
 7000        let (buffer, cursor_buffer_position) =
 7001            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7002
 7003        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7004            self.discard_edit_prediction(false, cx);
 7005            return None;
 7006        }
 7007
 7008        self.update_visible_edit_prediction(window, cx);
 7009
 7010        if !user_requested
 7011            && (!self.should_show_edit_predictions()
 7012                || !self.is_focused(window)
 7013                || buffer.read(cx).is_empty())
 7014        {
 7015            self.discard_edit_prediction(false, cx);
 7016            return None;
 7017        }
 7018
 7019        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7020        Some(())
 7021    }
 7022
 7023    fn show_edit_predictions_in_menu(&self) -> bool {
 7024        match self.edit_prediction_settings {
 7025            EditPredictionSettings::Disabled => false,
 7026            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7027        }
 7028    }
 7029
 7030    pub fn edit_predictions_enabled(&self) -> bool {
 7031        match self.edit_prediction_settings {
 7032            EditPredictionSettings::Disabled => false,
 7033            EditPredictionSettings::Enabled { .. } => true,
 7034        }
 7035    }
 7036
 7037    fn edit_prediction_requires_modifier(&self) -> bool {
 7038        match self.edit_prediction_settings {
 7039            EditPredictionSettings::Disabled => false,
 7040            EditPredictionSettings::Enabled {
 7041                preview_requires_modifier,
 7042                ..
 7043            } => preview_requires_modifier,
 7044        }
 7045    }
 7046
 7047    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7048        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7049            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7050            self.discard_edit_prediction(false, cx);
 7051        } else {
 7052            let selection = self.selections.newest_anchor();
 7053            let cursor = selection.head();
 7054
 7055            if let Some((buffer, cursor_buffer_position)) =
 7056                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7057            {
 7058                self.edit_prediction_settings =
 7059                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7060            }
 7061        }
 7062    }
 7063
 7064    fn edit_prediction_settings_at_position(
 7065        &self,
 7066        buffer: &Entity<Buffer>,
 7067        buffer_position: language::Anchor,
 7068        cx: &App,
 7069    ) -> EditPredictionSettings {
 7070        if !self.mode.is_full()
 7071            || !self.show_edit_predictions_override.unwrap_or(true)
 7072            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7073        {
 7074            return EditPredictionSettings::Disabled;
 7075        }
 7076
 7077        let buffer = buffer.read(cx);
 7078
 7079        let file = buffer.file();
 7080
 7081        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7082            return EditPredictionSettings::Disabled;
 7083        };
 7084
 7085        let by_provider = matches!(
 7086            self.menu_edit_predictions_policy,
 7087            MenuEditPredictionsPolicy::ByProvider
 7088        );
 7089
 7090        let show_in_menu = by_provider
 7091            && self
 7092                .edit_prediction_provider
 7093                .as_ref()
 7094                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7095
 7096        let preview_requires_modifier =
 7097            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7098
 7099        EditPredictionSettings::Enabled {
 7100            show_in_menu,
 7101            preview_requires_modifier,
 7102        }
 7103    }
 7104
 7105    fn should_show_edit_predictions(&self) -> bool {
 7106        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7107    }
 7108
 7109    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7110        matches!(
 7111            self.edit_prediction_preview,
 7112            EditPredictionPreview::Active { .. }
 7113        )
 7114    }
 7115
 7116    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7117        let cursor = self.selections.newest_anchor().head();
 7118        if let Some((buffer, cursor_position)) =
 7119            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7120        {
 7121            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7122        } else {
 7123            false
 7124        }
 7125    }
 7126
 7127    pub fn supports_minimap(&self, cx: &App) -> bool {
 7128        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7129    }
 7130
 7131    fn edit_predictions_enabled_in_buffer(
 7132        &self,
 7133        buffer: &Entity<Buffer>,
 7134        buffer_position: language::Anchor,
 7135        cx: &App,
 7136    ) -> bool {
 7137        maybe!({
 7138            if self.read_only(cx) {
 7139                return Some(false);
 7140            }
 7141            let provider = self.edit_prediction_provider()?;
 7142            if !provider.is_enabled(buffer, buffer_position, cx) {
 7143                return Some(false);
 7144            }
 7145            let buffer = buffer.read(cx);
 7146            let Some(file) = buffer.file() else {
 7147                return Some(true);
 7148            };
 7149            let settings = all_language_settings(Some(file), cx);
 7150            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7151        })
 7152        .unwrap_or(false)
 7153    }
 7154
 7155    fn cycle_edit_prediction(
 7156        &mut self,
 7157        direction: Direction,
 7158        window: &mut Window,
 7159        cx: &mut Context<Self>,
 7160    ) -> Option<()> {
 7161        let provider = self.edit_prediction_provider()?;
 7162        let cursor = self.selections.newest_anchor().head();
 7163        let (buffer, cursor_buffer_position) =
 7164            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7165        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7166            return None;
 7167        }
 7168
 7169        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7170        self.update_visible_edit_prediction(window, cx);
 7171
 7172        Some(())
 7173    }
 7174
 7175    pub fn show_edit_prediction(
 7176        &mut self,
 7177        _: &ShowEditPrediction,
 7178        window: &mut Window,
 7179        cx: &mut Context<Self>,
 7180    ) {
 7181        if !self.has_active_edit_prediction() {
 7182            self.refresh_edit_prediction(false, true, window, cx);
 7183            return;
 7184        }
 7185
 7186        self.update_visible_edit_prediction(window, cx);
 7187    }
 7188
 7189    pub fn display_cursor_names(
 7190        &mut self,
 7191        _: &DisplayCursorNames,
 7192        window: &mut Window,
 7193        cx: &mut Context<Self>,
 7194    ) {
 7195        self.show_cursor_names(window, cx);
 7196    }
 7197
 7198    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7199        self.show_cursor_names = true;
 7200        cx.notify();
 7201        cx.spawn_in(window, async move |this, cx| {
 7202            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7203            this.update(cx, |this, cx| {
 7204                this.show_cursor_names = false;
 7205                cx.notify()
 7206            })
 7207            .ok()
 7208        })
 7209        .detach();
 7210    }
 7211
 7212    pub fn next_edit_prediction(
 7213        &mut self,
 7214        _: &NextEditPrediction,
 7215        window: &mut Window,
 7216        cx: &mut Context<Self>,
 7217    ) {
 7218        if self.has_active_edit_prediction() {
 7219            self.cycle_edit_prediction(Direction::Next, window, cx);
 7220        } else {
 7221            let is_copilot_disabled = self
 7222                .refresh_edit_prediction(false, true, window, cx)
 7223                .is_none();
 7224            if is_copilot_disabled {
 7225                cx.propagate();
 7226            }
 7227        }
 7228    }
 7229
 7230    pub fn previous_edit_prediction(
 7231        &mut self,
 7232        _: &PreviousEditPrediction,
 7233        window: &mut Window,
 7234        cx: &mut Context<Self>,
 7235    ) {
 7236        if self.has_active_edit_prediction() {
 7237            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7238        } else {
 7239            let is_copilot_disabled = self
 7240                .refresh_edit_prediction(false, true, window, cx)
 7241                .is_none();
 7242            if is_copilot_disabled {
 7243                cx.propagate();
 7244            }
 7245        }
 7246    }
 7247
 7248    pub fn accept_edit_prediction(
 7249        &mut self,
 7250        _: &AcceptEditPrediction,
 7251        window: &mut Window,
 7252        cx: &mut Context<Self>,
 7253    ) {
 7254        if self.show_edit_predictions_in_menu() {
 7255            self.hide_context_menu(window, cx);
 7256        }
 7257
 7258        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7259            return;
 7260        };
 7261
 7262        match &active_edit_prediction.completion {
 7263            EditPrediction::MoveWithin { target, .. } => {
 7264                let target = *target;
 7265
 7266                if let Some(position_map) = &self.last_position_map {
 7267                    if position_map
 7268                        .visible_row_range
 7269                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7270                        || !self.edit_prediction_requires_modifier()
 7271                    {
 7272                        self.unfold_ranges(&[target..target], true, false, cx);
 7273                        // Note that this is also done in vim's handler of the Tab action.
 7274                        self.change_selections(
 7275                            SelectionEffects::scroll(Autoscroll::newest()),
 7276                            window,
 7277                            cx,
 7278                            |selections| {
 7279                                selections.select_anchor_ranges([target..target]);
 7280                            },
 7281                        );
 7282                        self.clear_row_highlights::<EditPredictionPreview>();
 7283
 7284                        self.edit_prediction_preview
 7285                            .set_previous_scroll_position(None);
 7286                    } else {
 7287                        self.edit_prediction_preview
 7288                            .set_previous_scroll_position(Some(
 7289                                position_map.snapshot.scroll_anchor,
 7290                            ));
 7291
 7292                        self.highlight_rows::<EditPredictionPreview>(
 7293                            target..target,
 7294                            cx.theme().colors().editor_highlighted_line_background,
 7295                            RowHighlightOptions {
 7296                                autoscroll: true,
 7297                                ..Default::default()
 7298                            },
 7299                            cx,
 7300                        );
 7301                        self.request_autoscroll(Autoscroll::fit(), cx);
 7302                    }
 7303                }
 7304            }
 7305            EditPrediction::MoveOutside { snapshot, target } => {
 7306                if let Some(workspace) = self.workspace() {
 7307                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7308                        .detach_and_log_err(cx);
 7309                }
 7310            }
 7311            EditPrediction::Edit { edits, .. } => {
 7312                self.report_edit_prediction_event(
 7313                    active_edit_prediction.completion_id.clone(),
 7314                    true,
 7315                    cx,
 7316                );
 7317
 7318                if let Some(provider) = self.edit_prediction_provider() {
 7319                    provider.accept(cx);
 7320                }
 7321
 7322                // Store the transaction ID and selections before applying the edit
 7323                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7324
 7325                let snapshot = self.buffer.read(cx).snapshot(cx);
 7326                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7327
 7328                self.buffer.update(cx, |buffer, cx| {
 7329                    buffer.edit(edits.iter().cloned(), None, cx)
 7330                });
 7331
 7332                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7333                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7334                });
 7335
 7336                let selections = self.selections.disjoint_anchors_arc();
 7337                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7338                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7339                    if has_new_transaction {
 7340                        self.selection_history
 7341                            .insert_transaction(transaction_id_now, selections);
 7342                    }
 7343                }
 7344
 7345                self.update_visible_edit_prediction(window, cx);
 7346                if self.active_edit_prediction.is_none() {
 7347                    self.refresh_edit_prediction(true, true, window, cx);
 7348                }
 7349
 7350                cx.notify();
 7351            }
 7352        }
 7353
 7354        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7355    }
 7356
 7357    pub fn accept_partial_edit_prediction(
 7358        &mut self,
 7359        _: &AcceptPartialEditPrediction,
 7360        window: &mut Window,
 7361        cx: &mut Context<Self>,
 7362    ) {
 7363        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7364            return;
 7365        };
 7366        if self.selections.count() != 1 {
 7367            return;
 7368        }
 7369
 7370        match &active_edit_prediction.completion {
 7371            EditPrediction::MoveWithin { target, .. } => {
 7372                let target = *target;
 7373                self.change_selections(
 7374                    SelectionEffects::scroll(Autoscroll::newest()),
 7375                    window,
 7376                    cx,
 7377                    |selections| {
 7378                        selections.select_anchor_ranges([target..target]);
 7379                    },
 7380                );
 7381            }
 7382            EditPrediction::MoveOutside { snapshot, target } => {
 7383                if let Some(workspace) = self.workspace() {
 7384                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7385                        .detach_and_log_err(cx);
 7386                }
 7387            }
 7388            EditPrediction::Edit { edits, .. } => {
 7389                self.report_edit_prediction_event(
 7390                    active_edit_prediction.completion_id.clone(),
 7391                    true,
 7392                    cx,
 7393                );
 7394
 7395                // Find an insertion that starts at the cursor position.
 7396                let snapshot = self.buffer.read(cx).snapshot(cx);
 7397                let cursor_offset = self
 7398                    .selections
 7399                    .newest::<usize>(&self.display_snapshot(cx))
 7400                    .head();
 7401                let insertion = edits.iter().find_map(|(range, text)| {
 7402                    let range = range.to_offset(&snapshot);
 7403                    if range.is_empty() && range.start == cursor_offset {
 7404                        Some(text)
 7405                    } else {
 7406                        None
 7407                    }
 7408                });
 7409
 7410                if let Some(text) = insertion {
 7411                    let mut partial_completion = text
 7412                        .chars()
 7413                        .by_ref()
 7414                        .take_while(|c| c.is_alphabetic())
 7415                        .collect::<String>();
 7416                    if partial_completion.is_empty() {
 7417                        partial_completion = text
 7418                            .chars()
 7419                            .by_ref()
 7420                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7421                            .collect::<String>();
 7422                    }
 7423
 7424                    cx.emit(EditorEvent::InputHandled {
 7425                        utf16_range_to_replace: None,
 7426                        text: partial_completion.clone().into(),
 7427                    });
 7428
 7429                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7430
 7431                    self.refresh_edit_prediction(true, true, window, cx);
 7432                    cx.notify();
 7433                } else {
 7434                    self.accept_edit_prediction(&Default::default(), window, cx);
 7435                }
 7436            }
 7437        }
 7438    }
 7439
 7440    fn discard_edit_prediction(
 7441        &mut self,
 7442        should_report_edit_prediction_event: bool,
 7443        cx: &mut Context<Self>,
 7444    ) -> bool {
 7445        if should_report_edit_prediction_event {
 7446            let completion_id = self
 7447                .active_edit_prediction
 7448                .as_ref()
 7449                .and_then(|active_completion| active_completion.completion_id.clone());
 7450
 7451            self.report_edit_prediction_event(completion_id, false, cx);
 7452        }
 7453
 7454        if let Some(provider) = self.edit_prediction_provider() {
 7455            provider.discard(cx);
 7456        }
 7457
 7458        self.take_active_edit_prediction(cx)
 7459    }
 7460
 7461    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7462        let Some(provider) = self.edit_prediction_provider() else {
 7463            return;
 7464        };
 7465
 7466        let Some((_, buffer, _)) = self
 7467            .buffer
 7468            .read(cx)
 7469            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7470        else {
 7471            return;
 7472        };
 7473
 7474        let extension = buffer
 7475            .read(cx)
 7476            .file()
 7477            .and_then(|file| Some(file.path().extension()?.to_string()));
 7478
 7479        let event_type = match accepted {
 7480            true => "Edit Prediction Accepted",
 7481            false => "Edit Prediction Discarded",
 7482        };
 7483        telemetry::event!(
 7484            event_type,
 7485            provider = provider.name(),
 7486            prediction_id = id,
 7487            suggestion_accepted = accepted,
 7488            file_extension = extension,
 7489        );
 7490    }
 7491
 7492    fn open_editor_at_anchor(
 7493        snapshot: &language::BufferSnapshot,
 7494        target: language::Anchor,
 7495        workspace: &Entity<Workspace>,
 7496        window: &mut Window,
 7497        cx: &mut App,
 7498    ) -> Task<Result<()>> {
 7499        workspace.update(cx, |workspace, cx| {
 7500            let path = snapshot.file().map(|file| file.full_path(cx));
 7501            let Some(path) =
 7502                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7503            else {
 7504                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7505            };
 7506            let target = text::ToPoint::to_point(&target, snapshot);
 7507            let item = workspace.open_path(path, None, true, window, cx);
 7508            window.spawn(cx, async move |cx| {
 7509                let Some(editor) = item.await?.downcast::<Editor>() else {
 7510                    return Ok(());
 7511                };
 7512                editor
 7513                    .update_in(cx, |editor, window, cx| {
 7514                        editor.go_to_singleton_buffer_point(target, window, cx);
 7515                    })
 7516                    .ok();
 7517                anyhow::Ok(())
 7518            })
 7519        })
 7520    }
 7521
 7522    pub fn has_active_edit_prediction(&self) -> bool {
 7523        self.active_edit_prediction.is_some()
 7524    }
 7525
 7526    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7527        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7528            return false;
 7529        };
 7530
 7531        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7532        self.clear_highlights::<EditPredictionHighlight>(cx);
 7533        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7534        true
 7535    }
 7536
 7537    /// Returns true when we're displaying the edit prediction popover below the cursor
 7538    /// like we are not previewing and the LSP autocomplete menu is visible
 7539    /// or we are in `when_holding_modifier` mode.
 7540    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7541        if self.edit_prediction_preview_is_active()
 7542            || !self.show_edit_predictions_in_menu()
 7543            || !self.edit_predictions_enabled()
 7544        {
 7545            return false;
 7546        }
 7547
 7548        if self.has_visible_completions_menu() {
 7549            return true;
 7550        }
 7551
 7552        has_completion && self.edit_prediction_requires_modifier()
 7553    }
 7554
 7555    fn handle_modifiers_changed(
 7556        &mut self,
 7557        modifiers: Modifiers,
 7558        position_map: &PositionMap,
 7559        window: &mut Window,
 7560        cx: &mut Context<Self>,
 7561    ) {
 7562        if self.show_edit_predictions_in_menu() {
 7563            self.update_edit_prediction_preview(&modifiers, window, cx);
 7564        }
 7565
 7566        self.update_selection_mode(&modifiers, position_map, window, cx);
 7567
 7568        let mouse_position = window.mouse_position();
 7569        if !position_map.text_hitbox.is_hovered(window) {
 7570            return;
 7571        }
 7572
 7573        self.update_hovered_link(
 7574            position_map.point_for_position(mouse_position),
 7575            &position_map.snapshot,
 7576            modifiers,
 7577            window,
 7578            cx,
 7579        )
 7580    }
 7581
 7582    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7583        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7584        if invert {
 7585            match multi_cursor_setting {
 7586                MultiCursorModifier::Alt => modifiers.alt,
 7587                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7588            }
 7589        } else {
 7590            match multi_cursor_setting {
 7591                MultiCursorModifier::Alt => modifiers.secondary(),
 7592                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7593            }
 7594        }
 7595    }
 7596
 7597    fn columnar_selection_mode(
 7598        modifiers: &Modifiers,
 7599        cx: &mut Context<Self>,
 7600    ) -> Option<ColumnarMode> {
 7601        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7602            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7603                Some(ColumnarMode::FromMouse)
 7604            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7605                Some(ColumnarMode::FromSelection)
 7606            } else {
 7607                None
 7608            }
 7609        } else {
 7610            None
 7611        }
 7612    }
 7613
 7614    fn update_selection_mode(
 7615        &mut self,
 7616        modifiers: &Modifiers,
 7617        position_map: &PositionMap,
 7618        window: &mut Window,
 7619        cx: &mut Context<Self>,
 7620    ) {
 7621        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7622            return;
 7623        };
 7624        if self.selections.pending_anchor().is_none() {
 7625            return;
 7626        }
 7627
 7628        let mouse_position = window.mouse_position();
 7629        let point_for_position = position_map.point_for_position(mouse_position);
 7630        let position = point_for_position.previous_valid;
 7631
 7632        self.select(
 7633            SelectPhase::BeginColumnar {
 7634                position,
 7635                reset: false,
 7636                mode,
 7637                goal_column: point_for_position.exact_unclipped.column(),
 7638            },
 7639            window,
 7640            cx,
 7641        );
 7642    }
 7643
 7644    fn update_edit_prediction_preview(
 7645        &mut self,
 7646        modifiers: &Modifiers,
 7647        window: &mut Window,
 7648        cx: &mut Context<Self>,
 7649    ) {
 7650        let mut modifiers_held = false;
 7651        if let Some(accept_keystroke) = self
 7652            .accept_edit_prediction_keybind(false, window, cx)
 7653            .keystroke()
 7654        {
 7655            modifiers_held = modifiers_held
 7656                || (accept_keystroke.modifiers() == modifiers
 7657                    && accept_keystroke.modifiers().modified());
 7658        };
 7659        if let Some(accept_partial_keystroke) = self
 7660            .accept_edit_prediction_keybind(true, window, cx)
 7661            .keystroke()
 7662        {
 7663            modifiers_held = modifiers_held
 7664                || (accept_partial_keystroke.modifiers() == modifiers
 7665                    && accept_partial_keystroke.modifiers().modified());
 7666        }
 7667
 7668        if modifiers_held {
 7669            if matches!(
 7670                self.edit_prediction_preview,
 7671                EditPredictionPreview::Inactive { .. }
 7672            ) {
 7673                self.edit_prediction_preview = EditPredictionPreview::Active {
 7674                    previous_scroll_position: None,
 7675                    since: Instant::now(),
 7676                };
 7677
 7678                self.update_visible_edit_prediction(window, cx);
 7679                cx.notify();
 7680            }
 7681        } else if let EditPredictionPreview::Active {
 7682            previous_scroll_position,
 7683            since,
 7684        } = self.edit_prediction_preview
 7685        {
 7686            if let (Some(previous_scroll_position), Some(position_map)) =
 7687                (previous_scroll_position, self.last_position_map.as_ref())
 7688            {
 7689                self.set_scroll_position(
 7690                    previous_scroll_position
 7691                        .scroll_position(&position_map.snapshot.display_snapshot),
 7692                    window,
 7693                    cx,
 7694                );
 7695            }
 7696
 7697            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7698                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7699            };
 7700            self.clear_row_highlights::<EditPredictionPreview>();
 7701            self.update_visible_edit_prediction(window, cx);
 7702            cx.notify();
 7703        }
 7704    }
 7705
 7706    fn update_visible_edit_prediction(
 7707        &mut self,
 7708        _window: &mut Window,
 7709        cx: &mut Context<Self>,
 7710    ) -> Option<()> {
 7711        if DisableAiSettings::get_global(cx).disable_ai {
 7712            return None;
 7713        }
 7714
 7715        if self.ime_transaction.is_some() {
 7716            self.discard_edit_prediction(false, cx);
 7717            return None;
 7718        }
 7719
 7720        let selection = self.selections.newest_anchor();
 7721        let cursor = selection.head();
 7722        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7723        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7724        let excerpt_id = cursor.excerpt_id;
 7725
 7726        let show_in_menu = self.show_edit_predictions_in_menu();
 7727        let completions_menu_has_precedence = !show_in_menu
 7728            && (self.context_menu.borrow().is_some()
 7729                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7730
 7731        if completions_menu_has_precedence
 7732            || !offset_selection.is_empty()
 7733            || self
 7734                .active_edit_prediction
 7735                .as_ref()
 7736                .is_some_and(|completion| {
 7737                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7738                        return false;
 7739                    };
 7740                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7741                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7742                    !invalidation_range.contains(&offset_selection.head())
 7743                })
 7744        {
 7745            self.discard_edit_prediction(false, cx);
 7746            return None;
 7747        }
 7748
 7749        self.take_active_edit_prediction(cx);
 7750        let Some(provider) = self.edit_prediction_provider() else {
 7751            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7752            return None;
 7753        };
 7754
 7755        let (buffer, cursor_buffer_position) =
 7756            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7757
 7758        self.edit_prediction_settings =
 7759            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7760
 7761        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7762
 7763        if self.edit_prediction_indent_conflict {
 7764            let cursor_point = cursor.to_point(&multibuffer);
 7765
 7766            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7767
 7768            if let Some((_, indent)) = indents.iter().next()
 7769                && indent.len == cursor_point.column
 7770            {
 7771                self.edit_prediction_indent_conflict = false;
 7772            }
 7773        }
 7774
 7775        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7776
 7777        let (completion_id, edits, edit_preview) = match edit_prediction {
 7778            edit_prediction::EditPrediction::Local {
 7779                id,
 7780                edits,
 7781                edit_preview,
 7782            } => (id, edits, edit_preview),
 7783            edit_prediction::EditPrediction::Jump {
 7784                id,
 7785                snapshot,
 7786                target,
 7787            } => {
 7788                self.stale_edit_prediction_in_menu = None;
 7789                self.active_edit_prediction = Some(EditPredictionState {
 7790                    inlay_ids: vec![],
 7791                    completion: EditPrediction::MoveOutside { snapshot, target },
 7792                    completion_id: id,
 7793                    invalidation_range: None,
 7794                });
 7795                cx.notify();
 7796                return Some(());
 7797            }
 7798        };
 7799
 7800        let edits = edits
 7801            .into_iter()
 7802            .flat_map(|(range, new_text)| {
 7803                Some((
 7804                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7805                    new_text,
 7806                ))
 7807            })
 7808            .collect::<Vec<_>>();
 7809        if edits.is_empty() {
 7810            return None;
 7811        }
 7812
 7813        let first_edit_start = edits.first().unwrap().0.start;
 7814        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7815        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7816
 7817        let last_edit_end = edits.last().unwrap().0.end;
 7818        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7819        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7820
 7821        let cursor_row = cursor.to_point(&multibuffer).row;
 7822
 7823        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7824
 7825        let mut inlay_ids = Vec::new();
 7826        let invalidation_row_range;
 7827        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7828            Some(cursor_row..edit_end_row)
 7829        } else if cursor_row > edit_end_row {
 7830            Some(edit_start_row..cursor_row)
 7831        } else {
 7832            None
 7833        };
 7834        let supports_jump = self
 7835            .edit_prediction_provider
 7836            .as_ref()
 7837            .map(|provider| provider.provider.supports_jump_to_edit())
 7838            .unwrap_or(true);
 7839
 7840        let is_move = supports_jump
 7841            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7842        let completion = if is_move {
 7843            invalidation_row_range =
 7844                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7845            let target = first_edit_start;
 7846            EditPrediction::MoveWithin { target, snapshot }
 7847        } else {
 7848            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7849                && !self.edit_predictions_hidden_for_vim_mode;
 7850
 7851            if show_completions_in_buffer {
 7852                if edits
 7853                    .iter()
 7854                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7855                {
 7856                    let mut inlays = Vec::new();
 7857                    for (range, new_text) in &edits {
 7858                        let inlay = Inlay::edit_prediction(
 7859                            post_inc(&mut self.next_inlay_id),
 7860                            range.start,
 7861                            new_text.as_str(),
 7862                        );
 7863                        inlay_ids.push(inlay.id);
 7864                        inlays.push(inlay);
 7865                    }
 7866
 7867                    self.splice_inlays(&[], inlays, cx);
 7868                } else {
 7869                    let background_color = cx.theme().status().deleted_background;
 7870                    self.highlight_text::<EditPredictionHighlight>(
 7871                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7872                        HighlightStyle {
 7873                            background_color: Some(background_color),
 7874                            ..Default::default()
 7875                        },
 7876                        cx,
 7877                    );
 7878                }
 7879            }
 7880
 7881            invalidation_row_range = edit_start_row..edit_end_row;
 7882
 7883            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7884                if provider.show_tab_accept_marker() {
 7885                    EditDisplayMode::TabAccept
 7886                } else {
 7887                    EditDisplayMode::Inline
 7888                }
 7889            } else {
 7890                EditDisplayMode::DiffPopover
 7891            };
 7892
 7893            EditPrediction::Edit {
 7894                edits,
 7895                edit_preview,
 7896                display_mode,
 7897                snapshot,
 7898            }
 7899        };
 7900
 7901        let invalidation_range = multibuffer
 7902            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7903            ..multibuffer.anchor_after(Point::new(
 7904                invalidation_row_range.end,
 7905                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7906            ));
 7907
 7908        self.stale_edit_prediction_in_menu = None;
 7909        self.active_edit_prediction = Some(EditPredictionState {
 7910            inlay_ids,
 7911            completion,
 7912            completion_id,
 7913            invalidation_range: Some(invalidation_range),
 7914        });
 7915
 7916        cx.notify();
 7917
 7918        Some(())
 7919    }
 7920
 7921    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7922        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7923    }
 7924
 7925    fn clear_tasks(&mut self) {
 7926        self.tasks.clear()
 7927    }
 7928
 7929    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7930        if self.tasks.insert(key, value).is_some() {
 7931            // This case should hopefully be rare, but just in case...
 7932            log::error!(
 7933                "multiple different run targets found on a single line, only the last target will be rendered"
 7934            )
 7935        }
 7936    }
 7937
 7938    /// Get all display points of breakpoints that will be rendered within editor
 7939    ///
 7940    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7941    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7942    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7943    fn active_breakpoints(
 7944        &self,
 7945        range: Range<DisplayRow>,
 7946        window: &mut Window,
 7947        cx: &mut Context<Self>,
 7948    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7949        let mut breakpoint_display_points = HashMap::default();
 7950
 7951        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7952            return breakpoint_display_points;
 7953        };
 7954
 7955        let snapshot = self.snapshot(window, cx);
 7956
 7957        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 7958        let Some(project) = self.project() else {
 7959            return breakpoint_display_points;
 7960        };
 7961
 7962        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7963            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7964
 7965        for (buffer_snapshot, range, excerpt_id) in
 7966            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7967        {
 7968            let Some(buffer) = project
 7969                .read(cx)
 7970                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7971            else {
 7972                continue;
 7973            };
 7974            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7975                &buffer,
 7976                Some(
 7977                    buffer_snapshot.anchor_before(range.start)
 7978                        ..buffer_snapshot.anchor_after(range.end),
 7979                ),
 7980                buffer_snapshot,
 7981                cx,
 7982            );
 7983            for (breakpoint, state) in breakpoints {
 7984                let multi_buffer_anchor =
 7985                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7986                let position = multi_buffer_anchor
 7987                    .to_point(&multi_buffer_snapshot)
 7988                    .to_display_point(&snapshot);
 7989
 7990                breakpoint_display_points.insert(
 7991                    position.row(),
 7992                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7993                );
 7994            }
 7995        }
 7996
 7997        breakpoint_display_points
 7998    }
 7999
 8000    fn breakpoint_context_menu(
 8001        &self,
 8002        anchor: Anchor,
 8003        window: &mut Window,
 8004        cx: &mut Context<Self>,
 8005    ) -> Entity<ui::ContextMenu> {
 8006        let weak_editor = cx.weak_entity();
 8007        let focus_handle = self.focus_handle(cx);
 8008
 8009        let row = self
 8010            .buffer
 8011            .read(cx)
 8012            .snapshot(cx)
 8013            .summary_for_anchor::<Point>(&anchor)
 8014            .row;
 8015
 8016        let breakpoint = self
 8017            .breakpoint_at_row(row, window, cx)
 8018            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8019
 8020        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8021            "Edit Log Breakpoint"
 8022        } else {
 8023            "Set Log Breakpoint"
 8024        };
 8025
 8026        let condition_breakpoint_msg = if breakpoint
 8027            .as_ref()
 8028            .is_some_and(|bp| bp.1.condition.is_some())
 8029        {
 8030            "Edit Condition Breakpoint"
 8031        } else {
 8032            "Set Condition Breakpoint"
 8033        };
 8034
 8035        let hit_condition_breakpoint_msg = if breakpoint
 8036            .as_ref()
 8037            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8038        {
 8039            "Edit Hit Condition Breakpoint"
 8040        } else {
 8041            "Set Hit Condition Breakpoint"
 8042        };
 8043
 8044        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8045            "Unset Breakpoint"
 8046        } else {
 8047            "Set Breakpoint"
 8048        };
 8049
 8050        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8051
 8052        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8053            BreakpointState::Enabled => Some("Disable"),
 8054            BreakpointState::Disabled => Some("Enable"),
 8055        });
 8056
 8057        let (anchor, breakpoint) =
 8058            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8059
 8060        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8061            menu.on_blur_subscription(Subscription::new(|| {}))
 8062                .context(focus_handle)
 8063                .when(run_to_cursor, |this| {
 8064                    let weak_editor = weak_editor.clone();
 8065                    this.entry("Run to cursor", None, move |window, cx| {
 8066                        weak_editor
 8067                            .update(cx, |editor, cx| {
 8068                                editor.change_selections(
 8069                                    SelectionEffects::no_scroll(),
 8070                                    window,
 8071                                    cx,
 8072                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8073                                );
 8074                            })
 8075                            .ok();
 8076
 8077                        window.dispatch_action(Box::new(RunToCursor), cx);
 8078                    })
 8079                    .separator()
 8080                })
 8081                .when_some(toggle_state_msg, |this, msg| {
 8082                    this.entry(msg, None, {
 8083                        let weak_editor = weak_editor.clone();
 8084                        let breakpoint = breakpoint.clone();
 8085                        move |_window, cx| {
 8086                            weak_editor
 8087                                .update(cx, |this, cx| {
 8088                                    this.edit_breakpoint_at_anchor(
 8089                                        anchor,
 8090                                        breakpoint.as_ref().clone(),
 8091                                        BreakpointEditAction::InvertState,
 8092                                        cx,
 8093                                    );
 8094                                })
 8095                                .log_err();
 8096                        }
 8097                    })
 8098                })
 8099                .entry(set_breakpoint_msg, None, {
 8100                    let weak_editor = weak_editor.clone();
 8101                    let breakpoint = breakpoint.clone();
 8102                    move |_window, cx| {
 8103                        weak_editor
 8104                            .update(cx, |this, cx| {
 8105                                this.edit_breakpoint_at_anchor(
 8106                                    anchor,
 8107                                    breakpoint.as_ref().clone(),
 8108                                    BreakpointEditAction::Toggle,
 8109                                    cx,
 8110                                );
 8111                            })
 8112                            .log_err();
 8113                    }
 8114                })
 8115                .entry(log_breakpoint_msg, None, {
 8116                    let breakpoint = breakpoint.clone();
 8117                    let weak_editor = weak_editor.clone();
 8118                    move |window, cx| {
 8119                        weak_editor
 8120                            .update(cx, |this, cx| {
 8121                                this.add_edit_breakpoint_block(
 8122                                    anchor,
 8123                                    breakpoint.as_ref(),
 8124                                    BreakpointPromptEditAction::Log,
 8125                                    window,
 8126                                    cx,
 8127                                );
 8128                            })
 8129                            .log_err();
 8130                    }
 8131                })
 8132                .entry(condition_breakpoint_msg, None, {
 8133                    let breakpoint = breakpoint.clone();
 8134                    let weak_editor = weak_editor.clone();
 8135                    move |window, cx| {
 8136                        weak_editor
 8137                            .update(cx, |this, cx| {
 8138                                this.add_edit_breakpoint_block(
 8139                                    anchor,
 8140                                    breakpoint.as_ref(),
 8141                                    BreakpointPromptEditAction::Condition,
 8142                                    window,
 8143                                    cx,
 8144                                );
 8145                            })
 8146                            .log_err();
 8147                    }
 8148                })
 8149                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8150                    weak_editor
 8151                        .update(cx, |this, cx| {
 8152                            this.add_edit_breakpoint_block(
 8153                                anchor,
 8154                                breakpoint.as_ref(),
 8155                                BreakpointPromptEditAction::HitCondition,
 8156                                window,
 8157                                cx,
 8158                            );
 8159                        })
 8160                        .log_err();
 8161                })
 8162        })
 8163    }
 8164
 8165    fn render_breakpoint(
 8166        &self,
 8167        position: Anchor,
 8168        row: DisplayRow,
 8169        breakpoint: &Breakpoint,
 8170        state: Option<BreakpointSessionState>,
 8171        cx: &mut Context<Self>,
 8172    ) -> IconButton {
 8173        let is_rejected = state.is_some_and(|s| !s.verified);
 8174        // Is it a breakpoint that shows up when hovering over gutter?
 8175        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8176            (false, false),
 8177            |PhantomBreakpointIndicator {
 8178                 is_active,
 8179                 display_row,
 8180                 collides_with_existing_breakpoint,
 8181             }| {
 8182                (
 8183                    is_active && display_row == row,
 8184                    collides_with_existing_breakpoint,
 8185                )
 8186            },
 8187        );
 8188
 8189        let (color, icon) = {
 8190            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8191                (false, false) => ui::IconName::DebugBreakpoint,
 8192                (true, false) => ui::IconName::DebugLogBreakpoint,
 8193                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8194                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8195            };
 8196
 8197            let color = if is_phantom {
 8198                Color::Hint
 8199            } else if is_rejected {
 8200                Color::Disabled
 8201            } else {
 8202                Color::Debugger
 8203            };
 8204
 8205            (color, icon)
 8206        };
 8207
 8208        let breakpoint = Arc::from(breakpoint.clone());
 8209
 8210        let alt_as_text = gpui::Keystroke {
 8211            modifiers: Modifiers::secondary_key(),
 8212            ..Default::default()
 8213        };
 8214        let primary_action_text = if breakpoint.is_disabled() {
 8215            "Enable breakpoint"
 8216        } else if is_phantom && !collides_with_existing {
 8217            "Set breakpoint"
 8218        } else {
 8219            "Unset breakpoint"
 8220        };
 8221        let focus_handle = self.focus_handle.clone();
 8222
 8223        let meta = if is_rejected {
 8224            SharedString::from("No executable code is associated with this line.")
 8225        } else if collides_with_existing && !breakpoint.is_disabled() {
 8226            SharedString::from(format!(
 8227                "{alt_as_text}-click to disable,\nright-click for more options."
 8228            ))
 8229        } else {
 8230            SharedString::from("Right-click for more options.")
 8231        };
 8232        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8233            .icon_size(IconSize::XSmall)
 8234            .size(ui::ButtonSize::None)
 8235            .when(is_rejected, |this| {
 8236                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8237            })
 8238            .icon_color(color)
 8239            .style(ButtonStyle::Transparent)
 8240            .on_click(cx.listener({
 8241                move |editor, event: &ClickEvent, window, cx| {
 8242                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8243                        BreakpointEditAction::InvertState
 8244                    } else {
 8245                        BreakpointEditAction::Toggle
 8246                    };
 8247
 8248                    window.focus(&editor.focus_handle(cx));
 8249                    editor.edit_breakpoint_at_anchor(
 8250                        position,
 8251                        breakpoint.as_ref().clone(),
 8252                        edit_action,
 8253                        cx,
 8254                    );
 8255                }
 8256            }))
 8257            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8258                editor.set_breakpoint_context_menu(
 8259                    row,
 8260                    Some(position),
 8261                    event.position(),
 8262                    window,
 8263                    cx,
 8264                );
 8265            }))
 8266            .tooltip(move |_window, cx| {
 8267                Tooltip::with_meta_in(
 8268                    primary_action_text,
 8269                    Some(&ToggleBreakpoint),
 8270                    meta.clone(),
 8271                    &focus_handle,
 8272                    cx,
 8273                )
 8274            })
 8275    }
 8276
 8277    fn build_tasks_context(
 8278        project: &Entity<Project>,
 8279        buffer: &Entity<Buffer>,
 8280        buffer_row: u32,
 8281        tasks: &Arc<RunnableTasks>,
 8282        cx: &mut Context<Self>,
 8283    ) -> Task<Option<task::TaskContext>> {
 8284        let position = Point::new(buffer_row, tasks.column);
 8285        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8286        let location = Location {
 8287            buffer: buffer.clone(),
 8288            range: range_start..range_start,
 8289        };
 8290        // Fill in the environmental variables from the tree-sitter captures
 8291        let mut captured_task_variables = TaskVariables::default();
 8292        for (capture_name, value) in tasks.extra_variables.clone() {
 8293            captured_task_variables.insert(
 8294                task::VariableName::Custom(capture_name.into()),
 8295                value.clone(),
 8296            );
 8297        }
 8298        project.update(cx, |project, cx| {
 8299            project.task_store().update(cx, |task_store, cx| {
 8300                task_store.task_context_for_location(captured_task_variables, location, cx)
 8301            })
 8302        })
 8303    }
 8304
 8305    pub fn spawn_nearest_task(
 8306        &mut self,
 8307        action: &SpawnNearestTask,
 8308        window: &mut Window,
 8309        cx: &mut Context<Self>,
 8310    ) {
 8311        let Some((workspace, _)) = self.workspace.clone() else {
 8312            return;
 8313        };
 8314        let Some(project) = self.project.clone() else {
 8315            return;
 8316        };
 8317
 8318        // Try to find a closest, enclosing node using tree-sitter that has a task
 8319        let Some((buffer, buffer_row, tasks)) = self
 8320            .find_enclosing_node_task(cx)
 8321            // Or find the task that's closest in row-distance.
 8322            .or_else(|| self.find_closest_task(cx))
 8323        else {
 8324            return;
 8325        };
 8326
 8327        let reveal_strategy = action.reveal;
 8328        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8329        cx.spawn_in(window, async move |_, cx| {
 8330            let context = task_context.await?;
 8331            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8332
 8333            let resolved = &mut resolved_task.resolved;
 8334            resolved.reveal = reveal_strategy;
 8335
 8336            workspace
 8337                .update_in(cx, |workspace, window, cx| {
 8338                    workspace.schedule_resolved_task(
 8339                        task_source_kind,
 8340                        resolved_task,
 8341                        false,
 8342                        window,
 8343                        cx,
 8344                    );
 8345                })
 8346                .ok()
 8347        })
 8348        .detach();
 8349    }
 8350
 8351    fn find_closest_task(
 8352        &mut self,
 8353        cx: &mut Context<Self>,
 8354    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8355        let cursor_row = self
 8356            .selections
 8357            .newest_adjusted(&self.display_snapshot(cx))
 8358            .head()
 8359            .row;
 8360
 8361        let ((buffer_id, row), tasks) = self
 8362            .tasks
 8363            .iter()
 8364            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8365
 8366        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8367        let tasks = Arc::new(tasks.to_owned());
 8368        Some((buffer, *row, tasks))
 8369    }
 8370
 8371    fn find_enclosing_node_task(
 8372        &mut self,
 8373        cx: &mut Context<Self>,
 8374    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8375        let snapshot = self.buffer.read(cx).snapshot(cx);
 8376        let offset = self
 8377            .selections
 8378            .newest::<usize>(&self.display_snapshot(cx))
 8379            .head();
 8380        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8381        let buffer_id = excerpt.buffer().remote_id();
 8382
 8383        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8384        let mut cursor = layer.node().walk();
 8385
 8386        while cursor.goto_first_child_for_byte(offset).is_some() {
 8387            if cursor.node().end_byte() == offset {
 8388                cursor.goto_next_sibling();
 8389            }
 8390        }
 8391
 8392        // Ascend to the smallest ancestor that contains the range and has a task.
 8393        loop {
 8394            let node = cursor.node();
 8395            let node_range = node.byte_range();
 8396            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8397
 8398            // Check if this node contains our offset
 8399            if node_range.start <= offset && node_range.end >= offset {
 8400                // If it contains offset, check for task
 8401                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8402                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8403                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8404                }
 8405            }
 8406
 8407            if !cursor.goto_parent() {
 8408                break;
 8409            }
 8410        }
 8411        None
 8412    }
 8413
 8414    fn render_run_indicator(
 8415        &self,
 8416        _style: &EditorStyle,
 8417        is_active: bool,
 8418        row: DisplayRow,
 8419        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8420        cx: &mut Context<Self>,
 8421    ) -> IconButton {
 8422        let color = Color::Muted;
 8423        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8424
 8425        IconButton::new(
 8426            ("run_indicator", row.0 as usize),
 8427            ui::IconName::PlayOutlined,
 8428        )
 8429        .shape(ui::IconButtonShape::Square)
 8430        .icon_size(IconSize::XSmall)
 8431        .icon_color(color)
 8432        .toggle_state(is_active)
 8433        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8434            let quick_launch = match e {
 8435                ClickEvent::Keyboard(_) => true,
 8436                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8437            };
 8438
 8439            window.focus(&editor.focus_handle(cx));
 8440            editor.toggle_code_actions(
 8441                &ToggleCodeActions {
 8442                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8443                    quick_launch,
 8444                },
 8445                window,
 8446                cx,
 8447            );
 8448        }))
 8449        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8450            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8451        }))
 8452    }
 8453
 8454    pub fn context_menu_visible(&self) -> bool {
 8455        !self.edit_prediction_preview_is_active()
 8456            && self
 8457                .context_menu
 8458                .borrow()
 8459                .as_ref()
 8460                .is_some_and(|menu| menu.visible())
 8461    }
 8462
 8463    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8464        self.context_menu
 8465            .borrow()
 8466            .as_ref()
 8467            .map(|menu| menu.origin())
 8468    }
 8469
 8470    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8471        self.context_menu_options = Some(options);
 8472    }
 8473
 8474    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8475    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8476
 8477    fn render_edit_prediction_popover(
 8478        &mut self,
 8479        text_bounds: &Bounds<Pixels>,
 8480        content_origin: gpui::Point<Pixels>,
 8481        right_margin: Pixels,
 8482        editor_snapshot: &EditorSnapshot,
 8483        visible_row_range: Range<DisplayRow>,
 8484        scroll_top: ScrollOffset,
 8485        scroll_bottom: ScrollOffset,
 8486        line_layouts: &[LineWithInvisibles],
 8487        line_height: Pixels,
 8488        scroll_position: gpui::Point<ScrollOffset>,
 8489        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8490        newest_selection_head: Option<DisplayPoint>,
 8491        editor_width: Pixels,
 8492        style: &EditorStyle,
 8493        window: &mut Window,
 8494        cx: &mut App,
 8495    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8496        if self.mode().is_minimap() {
 8497            return None;
 8498        }
 8499        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8500
 8501        if self.edit_prediction_visible_in_cursor_popover(true) {
 8502            return None;
 8503        }
 8504
 8505        match &active_edit_prediction.completion {
 8506            EditPrediction::MoveWithin { target, .. } => {
 8507                let target_display_point = target.to_display_point(editor_snapshot);
 8508
 8509                if self.edit_prediction_requires_modifier() {
 8510                    if !self.edit_prediction_preview_is_active() {
 8511                        return None;
 8512                    }
 8513
 8514                    self.render_edit_prediction_modifier_jump_popover(
 8515                        text_bounds,
 8516                        content_origin,
 8517                        visible_row_range,
 8518                        line_layouts,
 8519                        line_height,
 8520                        scroll_pixel_position,
 8521                        newest_selection_head,
 8522                        target_display_point,
 8523                        window,
 8524                        cx,
 8525                    )
 8526                } else {
 8527                    self.render_edit_prediction_eager_jump_popover(
 8528                        text_bounds,
 8529                        content_origin,
 8530                        editor_snapshot,
 8531                        visible_row_range,
 8532                        scroll_top,
 8533                        scroll_bottom,
 8534                        line_height,
 8535                        scroll_pixel_position,
 8536                        target_display_point,
 8537                        editor_width,
 8538                        window,
 8539                        cx,
 8540                    )
 8541                }
 8542            }
 8543            EditPrediction::Edit {
 8544                display_mode: EditDisplayMode::Inline,
 8545                ..
 8546            } => None,
 8547            EditPrediction::Edit {
 8548                display_mode: EditDisplayMode::TabAccept,
 8549                edits,
 8550                ..
 8551            } => {
 8552                let range = &edits.first()?.0;
 8553                let target_display_point = range.end.to_display_point(editor_snapshot);
 8554
 8555                self.render_edit_prediction_end_of_line_popover(
 8556                    "Accept",
 8557                    editor_snapshot,
 8558                    visible_row_range,
 8559                    target_display_point,
 8560                    line_height,
 8561                    scroll_pixel_position,
 8562                    content_origin,
 8563                    editor_width,
 8564                    window,
 8565                    cx,
 8566                )
 8567            }
 8568            EditPrediction::Edit {
 8569                edits,
 8570                edit_preview,
 8571                display_mode: EditDisplayMode::DiffPopover,
 8572                snapshot,
 8573            } => self.render_edit_prediction_diff_popover(
 8574                text_bounds,
 8575                content_origin,
 8576                right_margin,
 8577                editor_snapshot,
 8578                visible_row_range,
 8579                line_layouts,
 8580                line_height,
 8581                scroll_position,
 8582                scroll_pixel_position,
 8583                newest_selection_head,
 8584                editor_width,
 8585                style,
 8586                edits,
 8587                edit_preview,
 8588                snapshot,
 8589                window,
 8590                cx,
 8591            ),
 8592            EditPrediction::MoveOutside { snapshot, .. } => {
 8593                let file_name = snapshot
 8594                    .file()
 8595                    .map(|file| file.file_name(cx))
 8596                    .unwrap_or("untitled");
 8597                let mut element = self
 8598                    .render_edit_prediction_line_popover(
 8599                        format!("Jump to {file_name}"),
 8600                        Some(IconName::ZedPredict),
 8601                        window,
 8602                        cx,
 8603                    )
 8604                    .into_any();
 8605
 8606                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8607                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8608                let origin_y = text_bounds.size.height - size.height - px(30.);
 8609                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8610                element.prepaint_at(origin, window, cx);
 8611
 8612                Some((element, origin))
 8613            }
 8614        }
 8615    }
 8616
 8617    fn render_edit_prediction_modifier_jump_popover(
 8618        &mut self,
 8619        text_bounds: &Bounds<Pixels>,
 8620        content_origin: gpui::Point<Pixels>,
 8621        visible_row_range: Range<DisplayRow>,
 8622        line_layouts: &[LineWithInvisibles],
 8623        line_height: Pixels,
 8624        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8625        newest_selection_head: Option<DisplayPoint>,
 8626        target_display_point: DisplayPoint,
 8627        window: &mut Window,
 8628        cx: &mut App,
 8629    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8630        let scrolled_content_origin =
 8631            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8632
 8633        const SCROLL_PADDING_Y: Pixels = px(12.);
 8634
 8635        if target_display_point.row() < visible_row_range.start {
 8636            return self.render_edit_prediction_scroll_popover(
 8637                |_| SCROLL_PADDING_Y,
 8638                IconName::ArrowUp,
 8639                visible_row_range,
 8640                line_layouts,
 8641                newest_selection_head,
 8642                scrolled_content_origin,
 8643                window,
 8644                cx,
 8645            );
 8646        } else if target_display_point.row() >= visible_row_range.end {
 8647            return self.render_edit_prediction_scroll_popover(
 8648                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8649                IconName::ArrowDown,
 8650                visible_row_range,
 8651                line_layouts,
 8652                newest_selection_head,
 8653                scrolled_content_origin,
 8654                window,
 8655                cx,
 8656            );
 8657        }
 8658
 8659        const POLE_WIDTH: Pixels = px(2.);
 8660
 8661        let line_layout =
 8662            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8663        let target_column = target_display_point.column() as usize;
 8664
 8665        let target_x = line_layout.x_for_index(target_column);
 8666        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8667            - scroll_pixel_position.y;
 8668
 8669        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8670
 8671        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8672        border_color.l += 0.001;
 8673
 8674        let mut element = v_flex()
 8675            .items_end()
 8676            .when(flag_on_right, |el| el.items_start())
 8677            .child(if flag_on_right {
 8678                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8679                    .rounded_bl(px(0.))
 8680                    .rounded_tl(px(0.))
 8681                    .border_l_2()
 8682                    .border_color(border_color)
 8683            } else {
 8684                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8685                    .rounded_br(px(0.))
 8686                    .rounded_tr(px(0.))
 8687                    .border_r_2()
 8688                    .border_color(border_color)
 8689            })
 8690            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8691            .into_any();
 8692
 8693        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8694
 8695        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8696            - point(
 8697                if flag_on_right {
 8698                    POLE_WIDTH
 8699                } else {
 8700                    size.width - POLE_WIDTH
 8701                },
 8702                size.height - line_height,
 8703            );
 8704
 8705        origin.x = origin.x.max(content_origin.x);
 8706
 8707        element.prepaint_at(origin, window, cx);
 8708
 8709        Some((element, origin))
 8710    }
 8711
 8712    fn render_edit_prediction_scroll_popover(
 8713        &mut self,
 8714        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8715        scroll_icon: IconName,
 8716        visible_row_range: Range<DisplayRow>,
 8717        line_layouts: &[LineWithInvisibles],
 8718        newest_selection_head: Option<DisplayPoint>,
 8719        scrolled_content_origin: gpui::Point<Pixels>,
 8720        window: &mut Window,
 8721        cx: &mut App,
 8722    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8723        let mut element = self
 8724            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8725            .into_any();
 8726
 8727        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8728
 8729        let cursor = newest_selection_head?;
 8730        let cursor_row_layout =
 8731            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8732        let cursor_column = cursor.column() as usize;
 8733
 8734        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8735
 8736        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8737
 8738        element.prepaint_at(origin, window, cx);
 8739        Some((element, origin))
 8740    }
 8741
 8742    fn render_edit_prediction_eager_jump_popover(
 8743        &mut self,
 8744        text_bounds: &Bounds<Pixels>,
 8745        content_origin: gpui::Point<Pixels>,
 8746        editor_snapshot: &EditorSnapshot,
 8747        visible_row_range: Range<DisplayRow>,
 8748        scroll_top: ScrollOffset,
 8749        scroll_bottom: ScrollOffset,
 8750        line_height: Pixels,
 8751        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8752        target_display_point: DisplayPoint,
 8753        editor_width: Pixels,
 8754        window: &mut Window,
 8755        cx: &mut App,
 8756    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8757        if target_display_point.row().as_f64() < scroll_top {
 8758            let mut element = self
 8759                .render_edit_prediction_line_popover(
 8760                    "Jump to Edit",
 8761                    Some(IconName::ArrowUp),
 8762                    window,
 8763                    cx,
 8764                )
 8765                .into_any();
 8766
 8767            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8768            let offset = point(
 8769                (text_bounds.size.width - size.width) / 2.,
 8770                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8771            );
 8772
 8773            let origin = text_bounds.origin + offset;
 8774            element.prepaint_at(origin, window, cx);
 8775            Some((element, origin))
 8776        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8777            let mut element = self
 8778                .render_edit_prediction_line_popover(
 8779                    "Jump to Edit",
 8780                    Some(IconName::ArrowDown),
 8781                    window,
 8782                    cx,
 8783                )
 8784                .into_any();
 8785
 8786            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8787            let offset = point(
 8788                (text_bounds.size.width - size.width) / 2.,
 8789                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8790            );
 8791
 8792            let origin = text_bounds.origin + offset;
 8793            element.prepaint_at(origin, window, cx);
 8794            Some((element, origin))
 8795        } else {
 8796            self.render_edit_prediction_end_of_line_popover(
 8797                "Jump to Edit",
 8798                editor_snapshot,
 8799                visible_row_range,
 8800                target_display_point,
 8801                line_height,
 8802                scroll_pixel_position,
 8803                content_origin,
 8804                editor_width,
 8805                window,
 8806                cx,
 8807            )
 8808        }
 8809    }
 8810
 8811    fn render_edit_prediction_end_of_line_popover(
 8812        self: &mut Editor,
 8813        label: &'static str,
 8814        editor_snapshot: &EditorSnapshot,
 8815        visible_row_range: Range<DisplayRow>,
 8816        target_display_point: DisplayPoint,
 8817        line_height: Pixels,
 8818        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8819        content_origin: gpui::Point<Pixels>,
 8820        editor_width: Pixels,
 8821        window: &mut Window,
 8822        cx: &mut App,
 8823    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8824        let target_line_end = DisplayPoint::new(
 8825            target_display_point.row(),
 8826            editor_snapshot.line_len(target_display_point.row()),
 8827        );
 8828
 8829        let mut element = self
 8830            .render_edit_prediction_line_popover(label, None, window, cx)
 8831            .into_any();
 8832
 8833        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8834
 8835        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8836
 8837        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8838        let mut origin = start_point
 8839            + line_origin
 8840            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8841        origin.x = origin.x.max(content_origin.x);
 8842
 8843        let max_x = content_origin.x + editor_width - size.width;
 8844
 8845        if origin.x > max_x {
 8846            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8847
 8848            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8849                origin.y += offset;
 8850                IconName::ArrowUp
 8851            } else {
 8852                origin.y -= offset;
 8853                IconName::ArrowDown
 8854            };
 8855
 8856            element = self
 8857                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8858                .into_any();
 8859
 8860            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8861
 8862            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8863        }
 8864
 8865        element.prepaint_at(origin, window, cx);
 8866        Some((element, origin))
 8867    }
 8868
 8869    fn render_edit_prediction_diff_popover(
 8870        self: &Editor,
 8871        text_bounds: &Bounds<Pixels>,
 8872        content_origin: gpui::Point<Pixels>,
 8873        right_margin: Pixels,
 8874        editor_snapshot: &EditorSnapshot,
 8875        visible_row_range: Range<DisplayRow>,
 8876        line_layouts: &[LineWithInvisibles],
 8877        line_height: Pixels,
 8878        scroll_position: gpui::Point<ScrollOffset>,
 8879        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8880        newest_selection_head: Option<DisplayPoint>,
 8881        editor_width: Pixels,
 8882        style: &EditorStyle,
 8883        edits: &Vec<(Range<Anchor>, String)>,
 8884        edit_preview: &Option<language::EditPreview>,
 8885        snapshot: &language::BufferSnapshot,
 8886        window: &mut Window,
 8887        cx: &mut App,
 8888    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8889        let edit_start = edits
 8890            .first()
 8891            .unwrap()
 8892            .0
 8893            .start
 8894            .to_display_point(editor_snapshot);
 8895        let edit_end = edits
 8896            .last()
 8897            .unwrap()
 8898            .0
 8899            .end
 8900            .to_display_point(editor_snapshot);
 8901
 8902        let is_visible = visible_row_range.contains(&edit_start.row())
 8903            || visible_row_range.contains(&edit_end.row());
 8904        if !is_visible {
 8905            return None;
 8906        }
 8907
 8908        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8909            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8910        } else {
 8911            // Fallback for providers without edit_preview
 8912            crate::edit_prediction_fallback_text(edits, cx)
 8913        };
 8914
 8915        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8916        let line_count = highlighted_edits.text.lines().count();
 8917
 8918        const BORDER_WIDTH: Pixels = px(1.);
 8919
 8920        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8921        let has_keybind = keybind.is_some();
 8922
 8923        let mut element = h_flex()
 8924            .items_start()
 8925            .child(
 8926                h_flex()
 8927                    .bg(cx.theme().colors().editor_background)
 8928                    .border(BORDER_WIDTH)
 8929                    .shadow_xs()
 8930                    .border_color(cx.theme().colors().border)
 8931                    .rounded_l_lg()
 8932                    .when(line_count > 1, |el| el.rounded_br_lg())
 8933                    .pr_1()
 8934                    .child(styled_text),
 8935            )
 8936            .child(
 8937                h_flex()
 8938                    .h(line_height + BORDER_WIDTH * 2.)
 8939                    .px_1p5()
 8940                    .gap_1()
 8941                    // Workaround: For some reason, there's a gap if we don't do this
 8942                    .ml(-BORDER_WIDTH)
 8943                    .shadow(vec![gpui::BoxShadow {
 8944                        color: gpui::black().opacity(0.05),
 8945                        offset: point(px(1.), px(1.)),
 8946                        blur_radius: px(2.),
 8947                        spread_radius: px(0.),
 8948                    }])
 8949                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8950                    .border(BORDER_WIDTH)
 8951                    .border_color(cx.theme().colors().border)
 8952                    .rounded_r_lg()
 8953                    .id("edit_prediction_diff_popover_keybind")
 8954                    .when(!has_keybind, |el| {
 8955                        let status_colors = cx.theme().status();
 8956
 8957                        el.bg(status_colors.error_background)
 8958                            .border_color(status_colors.error.opacity(0.6))
 8959                            .child(Icon::new(IconName::Info).color(Color::Error))
 8960                            .cursor_default()
 8961                            .hoverable_tooltip(move |_window, cx| {
 8962                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8963                            })
 8964                    })
 8965                    .children(keybind),
 8966            )
 8967            .into_any();
 8968
 8969        let longest_row =
 8970            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8971        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8972            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8973        } else {
 8974            layout_line(
 8975                longest_row,
 8976                editor_snapshot,
 8977                style,
 8978                editor_width,
 8979                |_| false,
 8980                window,
 8981                cx,
 8982            )
 8983            .width
 8984        };
 8985
 8986        let viewport_bounds =
 8987            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8988                right: -right_margin,
 8989                ..Default::default()
 8990            });
 8991
 8992        let x_after_longest = Pixels::from(
 8993            ScrollPixelOffset::from(
 8994                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 8995            ) - scroll_pixel_position.x,
 8996        );
 8997
 8998        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8999
 9000        // Fully visible if it can be displayed within the window (allow overlapping other
 9001        // panes). However, this is only allowed if the popover starts within text_bounds.
 9002        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9003            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9004
 9005        let mut origin = if can_position_to_the_right {
 9006            point(
 9007                x_after_longest,
 9008                text_bounds.origin.y
 9009                    + Pixels::from(
 9010                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9011                            - scroll_pixel_position.y,
 9012                    ),
 9013            )
 9014        } else {
 9015            let cursor_row = newest_selection_head.map(|head| head.row());
 9016            let above_edit = edit_start
 9017                .row()
 9018                .0
 9019                .checked_sub(line_count as u32)
 9020                .map(DisplayRow);
 9021            let below_edit = Some(edit_end.row() + 1);
 9022            let above_cursor =
 9023                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9024            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9025
 9026            // Place the edit popover adjacent to the edit if there is a location
 9027            // available that is onscreen and does not obscure the cursor. Otherwise,
 9028            // place it adjacent to the cursor.
 9029            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9030                .into_iter()
 9031                .flatten()
 9032                .find(|&start_row| {
 9033                    let end_row = start_row + line_count as u32;
 9034                    visible_row_range.contains(&start_row)
 9035                        && visible_row_range.contains(&end_row)
 9036                        && cursor_row
 9037                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9038                })?;
 9039
 9040            content_origin
 9041                + point(
 9042                    Pixels::from(-scroll_pixel_position.x),
 9043                    Pixels::from(
 9044                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9045                    ),
 9046                )
 9047        };
 9048
 9049        origin.x -= BORDER_WIDTH;
 9050
 9051        window.defer_draw(element, origin, 1);
 9052
 9053        // Do not return an element, since it will already be drawn due to defer_draw.
 9054        None
 9055    }
 9056
 9057    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9058        px(30.)
 9059    }
 9060
 9061    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9062        if self.read_only(cx) {
 9063            cx.theme().players().read_only()
 9064        } else {
 9065            self.style.as_ref().unwrap().local_player
 9066        }
 9067    }
 9068
 9069    fn render_edit_prediction_accept_keybind(
 9070        &self,
 9071        window: &mut Window,
 9072        cx: &mut App,
 9073    ) -> Option<AnyElement> {
 9074        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9075        let accept_keystroke = accept_binding.keystroke()?;
 9076
 9077        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9078
 9079        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9080            Color::Accent
 9081        } else {
 9082            Color::Muted
 9083        };
 9084
 9085        h_flex()
 9086            .px_0p5()
 9087            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9088            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9089            .text_size(TextSize::XSmall.rems(cx))
 9090            .child(h_flex().children(ui::render_modifiers(
 9091                accept_keystroke.modifiers(),
 9092                PlatformStyle::platform(),
 9093                Some(modifiers_color),
 9094                Some(IconSize::XSmall.rems().into()),
 9095                true,
 9096            )))
 9097            .when(is_platform_style_mac, |parent| {
 9098                parent.child(accept_keystroke.key().to_string())
 9099            })
 9100            .when(!is_platform_style_mac, |parent| {
 9101                parent.child(
 9102                    Key::new(
 9103                        util::capitalize(accept_keystroke.key()),
 9104                        Some(Color::Default),
 9105                    )
 9106                    .size(Some(IconSize::XSmall.rems().into())),
 9107                )
 9108            })
 9109            .into_any()
 9110            .into()
 9111    }
 9112
 9113    fn render_edit_prediction_line_popover(
 9114        &self,
 9115        label: impl Into<SharedString>,
 9116        icon: Option<IconName>,
 9117        window: &mut Window,
 9118        cx: &mut App,
 9119    ) -> Stateful<Div> {
 9120        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9121
 9122        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9123        let has_keybind = keybind.is_some();
 9124
 9125        h_flex()
 9126            .id("ep-line-popover")
 9127            .py_0p5()
 9128            .pl_1()
 9129            .pr(padding_right)
 9130            .gap_1()
 9131            .rounded_md()
 9132            .border_1()
 9133            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9134            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9135            .shadow_xs()
 9136            .when(!has_keybind, |el| {
 9137                let status_colors = cx.theme().status();
 9138
 9139                el.bg(status_colors.error_background)
 9140                    .border_color(status_colors.error.opacity(0.6))
 9141                    .pl_2()
 9142                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9143                    .cursor_default()
 9144                    .hoverable_tooltip(move |_window, cx| {
 9145                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9146                    })
 9147            })
 9148            .children(keybind)
 9149            .child(
 9150                Label::new(label)
 9151                    .size(LabelSize::Small)
 9152                    .when(!has_keybind, |el| {
 9153                        el.color(cx.theme().status().error.into()).strikethrough()
 9154                    }),
 9155            )
 9156            .when(!has_keybind, |el| {
 9157                el.child(
 9158                    h_flex().ml_1().child(
 9159                        Icon::new(IconName::Info)
 9160                            .size(IconSize::Small)
 9161                            .color(cx.theme().status().error.into()),
 9162                    ),
 9163                )
 9164            })
 9165            .when_some(icon, |element, icon| {
 9166                element.child(
 9167                    div()
 9168                        .mt(px(1.5))
 9169                        .child(Icon::new(icon).size(IconSize::Small)),
 9170                )
 9171            })
 9172    }
 9173
 9174    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9175        let accent_color = cx.theme().colors().text_accent;
 9176        let editor_bg_color = cx.theme().colors().editor_background;
 9177        editor_bg_color.blend(accent_color.opacity(0.1))
 9178    }
 9179
 9180    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9181        let accent_color = cx.theme().colors().text_accent;
 9182        let editor_bg_color = cx.theme().colors().editor_background;
 9183        editor_bg_color.blend(accent_color.opacity(0.6))
 9184    }
 9185    fn get_prediction_provider_icon_name(
 9186        provider: &Option<RegisteredEditPredictionProvider>,
 9187    ) -> IconName {
 9188        match provider {
 9189            Some(provider) => match provider.provider.name() {
 9190                "copilot" => IconName::Copilot,
 9191                "supermaven" => IconName::Supermaven,
 9192                _ => IconName::ZedPredict,
 9193            },
 9194            None => IconName::ZedPredict,
 9195        }
 9196    }
 9197
 9198    fn render_edit_prediction_cursor_popover(
 9199        &self,
 9200        min_width: Pixels,
 9201        max_width: Pixels,
 9202        cursor_point: Point,
 9203        style: &EditorStyle,
 9204        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9205        _window: &Window,
 9206        cx: &mut Context<Editor>,
 9207    ) -> Option<AnyElement> {
 9208        let provider = self.edit_prediction_provider.as_ref()?;
 9209        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9210
 9211        let is_refreshing = provider.provider.is_refreshing(cx);
 9212
 9213        fn pending_completion_container(icon: IconName) -> Div {
 9214            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9215        }
 9216
 9217        let completion = match &self.active_edit_prediction {
 9218            Some(prediction) => {
 9219                if !self.has_visible_completions_menu() {
 9220                    const RADIUS: Pixels = px(6.);
 9221                    const BORDER_WIDTH: Pixels = px(1.);
 9222
 9223                    return Some(
 9224                        h_flex()
 9225                            .elevation_2(cx)
 9226                            .border(BORDER_WIDTH)
 9227                            .border_color(cx.theme().colors().border)
 9228                            .when(accept_keystroke.is_none(), |el| {
 9229                                el.border_color(cx.theme().status().error)
 9230                            })
 9231                            .rounded(RADIUS)
 9232                            .rounded_tl(px(0.))
 9233                            .overflow_hidden()
 9234                            .child(div().px_1p5().child(match &prediction.completion {
 9235                                EditPrediction::MoveWithin { target, snapshot } => {
 9236                                    use text::ToPoint as _;
 9237                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9238                                    {
 9239                                        Icon::new(IconName::ZedPredictDown)
 9240                                    } else {
 9241                                        Icon::new(IconName::ZedPredictUp)
 9242                                    }
 9243                                }
 9244                                EditPrediction::MoveOutside { .. } => {
 9245                                    // TODO [zeta2] custom icon for external jump?
 9246                                    Icon::new(provider_icon)
 9247                                }
 9248                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9249                            }))
 9250                            .child(
 9251                                h_flex()
 9252                                    .gap_1()
 9253                                    .py_1()
 9254                                    .px_2()
 9255                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9256                                    .border_l_1()
 9257                                    .border_color(cx.theme().colors().border)
 9258                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9259                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9260                                        el.child(
 9261                                            Label::new("Hold")
 9262                                                .size(LabelSize::Small)
 9263                                                .when(accept_keystroke.is_none(), |el| {
 9264                                                    el.strikethrough()
 9265                                                })
 9266                                                .line_height_style(LineHeightStyle::UiLabel),
 9267                                        )
 9268                                    })
 9269                                    .id("edit_prediction_cursor_popover_keybind")
 9270                                    .when(accept_keystroke.is_none(), |el| {
 9271                                        let status_colors = cx.theme().status();
 9272
 9273                                        el.bg(status_colors.error_background)
 9274                                            .border_color(status_colors.error.opacity(0.6))
 9275                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9276                                            .cursor_default()
 9277                                            .hoverable_tooltip(move |_window, cx| {
 9278                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9279                                                    .into()
 9280                                            })
 9281                                    })
 9282                                    .when_some(
 9283                                        accept_keystroke.as_ref(),
 9284                                        |el, accept_keystroke| {
 9285                                            el.child(h_flex().children(ui::render_modifiers(
 9286                                                accept_keystroke.modifiers(),
 9287                                                PlatformStyle::platform(),
 9288                                                Some(Color::Default),
 9289                                                Some(IconSize::XSmall.rems().into()),
 9290                                                false,
 9291                                            )))
 9292                                        },
 9293                                    ),
 9294                            )
 9295                            .into_any(),
 9296                    );
 9297                }
 9298
 9299                self.render_edit_prediction_cursor_popover_preview(
 9300                    prediction,
 9301                    cursor_point,
 9302                    style,
 9303                    cx,
 9304                )?
 9305            }
 9306
 9307            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9308                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9309                    stale_completion,
 9310                    cursor_point,
 9311                    style,
 9312                    cx,
 9313                )?,
 9314
 9315                None => pending_completion_container(provider_icon)
 9316                    .child(Label::new("...").size(LabelSize::Small)),
 9317            },
 9318
 9319            None => pending_completion_container(provider_icon)
 9320                .child(Label::new("...").size(LabelSize::Small)),
 9321        };
 9322
 9323        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9324            completion
 9325                .with_animation(
 9326                    "loading-completion",
 9327                    Animation::new(Duration::from_secs(2))
 9328                        .repeat()
 9329                        .with_easing(pulsating_between(0.4, 0.8)),
 9330                    |label, delta| label.opacity(delta),
 9331                )
 9332                .into_any_element()
 9333        } else {
 9334            completion.into_any_element()
 9335        };
 9336
 9337        let has_completion = self.active_edit_prediction.is_some();
 9338
 9339        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9340        Some(
 9341            h_flex()
 9342                .min_w(min_width)
 9343                .max_w(max_width)
 9344                .flex_1()
 9345                .elevation_2(cx)
 9346                .border_color(cx.theme().colors().border)
 9347                .child(
 9348                    div()
 9349                        .flex_1()
 9350                        .py_1()
 9351                        .px_2()
 9352                        .overflow_hidden()
 9353                        .child(completion),
 9354                )
 9355                .when_some(accept_keystroke, |el, accept_keystroke| {
 9356                    if !accept_keystroke.modifiers().modified() {
 9357                        return el;
 9358                    }
 9359
 9360                    el.child(
 9361                        h_flex()
 9362                            .h_full()
 9363                            .border_l_1()
 9364                            .rounded_r_lg()
 9365                            .border_color(cx.theme().colors().border)
 9366                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9367                            .gap_1()
 9368                            .py_1()
 9369                            .px_2()
 9370                            .child(
 9371                                h_flex()
 9372                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9373                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9374                                    .child(h_flex().children(ui::render_modifiers(
 9375                                        accept_keystroke.modifiers(),
 9376                                        PlatformStyle::platform(),
 9377                                        Some(if !has_completion {
 9378                                            Color::Muted
 9379                                        } else {
 9380                                            Color::Default
 9381                                        }),
 9382                                        None,
 9383                                        false,
 9384                                    ))),
 9385                            )
 9386                            .child(Label::new("Preview").into_any_element())
 9387                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9388                    )
 9389                })
 9390                .into_any(),
 9391        )
 9392    }
 9393
 9394    fn render_edit_prediction_cursor_popover_preview(
 9395        &self,
 9396        completion: &EditPredictionState,
 9397        cursor_point: Point,
 9398        style: &EditorStyle,
 9399        cx: &mut Context<Editor>,
 9400    ) -> Option<Div> {
 9401        use text::ToPoint as _;
 9402
 9403        fn render_relative_row_jump(
 9404            prefix: impl Into<String>,
 9405            current_row: u32,
 9406            target_row: u32,
 9407        ) -> Div {
 9408            let (row_diff, arrow) = if target_row < current_row {
 9409                (current_row - target_row, IconName::ArrowUp)
 9410            } else {
 9411                (target_row - current_row, IconName::ArrowDown)
 9412            };
 9413
 9414            h_flex()
 9415                .child(
 9416                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9417                        .color(Color::Muted)
 9418                        .size(LabelSize::Small),
 9419                )
 9420                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9421        }
 9422
 9423        let supports_jump = self
 9424            .edit_prediction_provider
 9425            .as_ref()
 9426            .map(|provider| provider.provider.supports_jump_to_edit())
 9427            .unwrap_or(true);
 9428
 9429        match &completion.completion {
 9430            EditPrediction::MoveWithin {
 9431                target, snapshot, ..
 9432            } => {
 9433                if !supports_jump {
 9434                    return None;
 9435                }
 9436
 9437                Some(
 9438                    h_flex()
 9439                        .px_2()
 9440                        .gap_2()
 9441                        .flex_1()
 9442                        .child(
 9443                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9444                                Icon::new(IconName::ZedPredictDown)
 9445                            } else {
 9446                                Icon::new(IconName::ZedPredictUp)
 9447                            },
 9448                        )
 9449                        .child(Label::new("Jump to Edit")),
 9450                )
 9451            }
 9452            EditPrediction::MoveOutside { snapshot, .. } => {
 9453                let file_name = snapshot
 9454                    .file()
 9455                    .map(|file| file.file_name(cx))
 9456                    .unwrap_or("untitled");
 9457                Some(
 9458                    h_flex()
 9459                        .px_2()
 9460                        .gap_2()
 9461                        .flex_1()
 9462                        .child(Icon::new(IconName::ZedPredict))
 9463                        .child(Label::new(format!("Jump to {file_name}"))),
 9464                )
 9465            }
 9466            EditPrediction::Edit {
 9467                edits,
 9468                edit_preview,
 9469                snapshot,
 9470                display_mode: _,
 9471            } => {
 9472                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9473
 9474                let (highlighted_edits, has_more_lines) =
 9475                    if let Some(edit_preview) = edit_preview.as_ref() {
 9476                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9477                            .first_line_preview()
 9478                    } else {
 9479                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9480                    };
 9481
 9482                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9483                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9484
 9485                let preview = h_flex()
 9486                    .gap_1()
 9487                    .min_w_16()
 9488                    .child(styled_text)
 9489                    .when(has_more_lines, |parent| parent.child(""));
 9490
 9491                let left = if supports_jump && first_edit_row != cursor_point.row {
 9492                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9493                        .into_any_element()
 9494                } else {
 9495                    let icon_name =
 9496                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9497                    Icon::new(icon_name).into_any_element()
 9498                };
 9499
 9500                Some(
 9501                    h_flex()
 9502                        .h_full()
 9503                        .flex_1()
 9504                        .gap_2()
 9505                        .pr_1()
 9506                        .overflow_x_hidden()
 9507                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9508                        .child(left)
 9509                        .child(preview),
 9510                )
 9511            }
 9512        }
 9513    }
 9514
 9515    pub fn render_context_menu(
 9516        &self,
 9517        style: &EditorStyle,
 9518        max_height_in_lines: u32,
 9519        window: &mut Window,
 9520        cx: &mut Context<Editor>,
 9521    ) -> Option<AnyElement> {
 9522        let menu = self.context_menu.borrow();
 9523        let menu = menu.as_ref()?;
 9524        if !menu.visible() {
 9525            return None;
 9526        };
 9527        Some(menu.render(style, max_height_in_lines, window, cx))
 9528    }
 9529
 9530    fn render_context_menu_aside(
 9531        &mut self,
 9532        max_size: Size<Pixels>,
 9533        window: &mut Window,
 9534        cx: &mut Context<Editor>,
 9535    ) -> Option<AnyElement> {
 9536        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9537            if menu.visible() {
 9538                menu.render_aside(max_size, window, cx)
 9539            } else {
 9540                None
 9541            }
 9542        })
 9543    }
 9544
 9545    fn hide_context_menu(
 9546        &mut self,
 9547        window: &mut Window,
 9548        cx: &mut Context<Self>,
 9549    ) -> Option<CodeContextMenu> {
 9550        cx.notify();
 9551        self.completion_tasks.clear();
 9552        let context_menu = self.context_menu.borrow_mut().take();
 9553        self.stale_edit_prediction_in_menu.take();
 9554        self.update_visible_edit_prediction(window, cx);
 9555        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9556            && let Some(completion_provider) = &self.completion_provider
 9557        {
 9558            completion_provider.selection_changed(None, window, cx);
 9559        }
 9560        context_menu
 9561    }
 9562
 9563    fn show_snippet_choices(
 9564        &mut self,
 9565        choices: &Vec<String>,
 9566        selection: Range<Anchor>,
 9567        cx: &mut Context<Self>,
 9568    ) {
 9569        let Some((_, buffer, _)) = self
 9570            .buffer()
 9571            .read(cx)
 9572            .excerpt_containing(selection.start, cx)
 9573        else {
 9574            return;
 9575        };
 9576        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9577        else {
 9578            return;
 9579        };
 9580        if buffer != end_buffer {
 9581            log::error!("expected anchor range to have matching buffer IDs");
 9582            return;
 9583        }
 9584
 9585        let id = post_inc(&mut self.next_completion_id);
 9586        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9587        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9588            CompletionsMenu::new_snippet_choices(
 9589                id,
 9590                true,
 9591                choices,
 9592                selection,
 9593                buffer,
 9594                snippet_sort_order,
 9595            ),
 9596        ));
 9597    }
 9598
 9599    pub fn insert_snippet(
 9600        &mut self,
 9601        insertion_ranges: &[Range<usize>],
 9602        snippet: Snippet,
 9603        window: &mut Window,
 9604        cx: &mut Context<Self>,
 9605    ) -> Result<()> {
 9606        struct Tabstop<T> {
 9607            is_end_tabstop: bool,
 9608            ranges: Vec<Range<T>>,
 9609            choices: Option<Vec<String>>,
 9610        }
 9611
 9612        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9613            let snippet_text: Arc<str> = snippet.text.clone().into();
 9614            let edits = insertion_ranges
 9615                .iter()
 9616                .cloned()
 9617                .map(|range| (range, snippet_text.clone()));
 9618            let autoindent_mode = AutoindentMode::Block {
 9619                original_indent_columns: Vec::new(),
 9620            };
 9621            buffer.edit(edits, Some(autoindent_mode), cx);
 9622
 9623            let snapshot = &*buffer.read(cx);
 9624            let snippet = &snippet;
 9625            snippet
 9626                .tabstops
 9627                .iter()
 9628                .map(|tabstop| {
 9629                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9630                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9631                    });
 9632                    let mut tabstop_ranges = tabstop
 9633                        .ranges
 9634                        .iter()
 9635                        .flat_map(|tabstop_range| {
 9636                            let mut delta = 0_isize;
 9637                            insertion_ranges.iter().map(move |insertion_range| {
 9638                                let insertion_start = insertion_range.start as isize + delta;
 9639                                delta +=
 9640                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9641
 9642                                let start = ((insertion_start + tabstop_range.start) as usize)
 9643                                    .min(snapshot.len());
 9644                                let end = ((insertion_start + tabstop_range.end) as usize)
 9645                                    .min(snapshot.len());
 9646                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9647                            })
 9648                        })
 9649                        .collect::<Vec<_>>();
 9650                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9651
 9652                    Tabstop {
 9653                        is_end_tabstop,
 9654                        ranges: tabstop_ranges,
 9655                        choices: tabstop.choices.clone(),
 9656                    }
 9657                })
 9658                .collect::<Vec<_>>()
 9659        });
 9660        if let Some(tabstop) = tabstops.first() {
 9661            self.change_selections(Default::default(), window, cx, |s| {
 9662                // Reverse order so that the first range is the newest created selection.
 9663                // Completions will use it and autoscroll will prioritize it.
 9664                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9665            });
 9666
 9667            if let Some(choices) = &tabstop.choices
 9668                && let Some(selection) = tabstop.ranges.first()
 9669            {
 9670                self.show_snippet_choices(choices, selection.clone(), cx)
 9671            }
 9672
 9673            // If we're already at the last tabstop and it's at the end of the snippet,
 9674            // we're done, we don't need to keep the state around.
 9675            if !tabstop.is_end_tabstop {
 9676                let choices = tabstops
 9677                    .iter()
 9678                    .map(|tabstop| tabstop.choices.clone())
 9679                    .collect();
 9680
 9681                let ranges = tabstops
 9682                    .into_iter()
 9683                    .map(|tabstop| tabstop.ranges)
 9684                    .collect::<Vec<_>>();
 9685
 9686                self.snippet_stack.push(SnippetState {
 9687                    active_index: 0,
 9688                    ranges,
 9689                    choices,
 9690                });
 9691            }
 9692
 9693            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9694            if self.autoclose_regions.is_empty() {
 9695                let snapshot = self.buffer.read(cx).snapshot(cx);
 9696                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9697                    let selection_head = selection.head();
 9698                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9699                        continue;
 9700                    };
 9701
 9702                    let mut bracket_pair = None;
 9703                    let max_lookup_length = scope
 9704                        .brackets()
 9705                        .map(|(pair, _)| {
 9706                            pair.start
 9707                                .as_str()
 9708                                .chars()
 9709                                .count()
 9710                                .max(pair.end.as_str().chars().count())
 9711                        })
 9712                        .max();
 9713                    if let Some(max_lookup_length) = max_lookup_length {
 9714                        let next_text = snapshot
 9715                            .chars_at(selection_head)
 9716                            .take(max_lookup_length)
 9717                            .collect::<String>();
 9718                        let prev_text = snapshot
 9719                            .reversed_chars_at(selection_head)
 9720                            .take(max_lookup_length)
 9721                            .collect::<String>();
 9722
 9723                        for (pair, enabled) in scope.brackets() {
 9724                            if enabled
 9725                                && pair.close
 9726                                && prev_text.starts_with(pair.start.as_str())
 9727                                && next_text.starts_with(pair.end.as_str())
 9728                            {
 9729                                bracket_pair = Some(pair.clone());
 9730                                break;
 9731                            }
 9732                        }
 9733                    }
 9734
 9735                    if let Some(pair) = bracket_pair {
 9736                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9737                        let autoclose_enabled =
 9738                            self.use_autoclose && snapshot_settings.use_autoclose;
 9739                        if autoclose_enabled {
 9740                            let start = snapshot.anchor_after(selection_head);
 9741                            let end = snapshot.anchor_after(selection_head);
 9742                            self.autoclose_regions.push(AutocloseRegion {
 9743                                selection_id: selection.id,
 9744                                range: start..end,
 9745                                pair,
 9746                            });
 9747                        }
 9748                    }
 9749                }
 9750            }
 9751        }
 9752        Ok(())
 9753    }
 9754
 9755    pub fn move_to_next_snippet_tabstop(
 9756        &mut self,
 9757        window: &mut Window,
 9758        cx: &mut Context<Self>,
 9759    ) -> bool {
 9760        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9761    }
 9762
 9763    pub fn move_to_prev_snippet_tabstop(
 9764        &mut self,
 9765        window: &mut Window,
 9766        cx: &mut Context<Self>,
 9767    ) -> bool {
 9768        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9769    }
 9770
 9771    pub fn move_to_snippet_tabstop(
 9772        &mut self,
 9773        bias: Bias,
 9774        window: &mut Window,
 9775        cx: &mut Context<Self>,
 9776    ) -> bool {
 9777        if let Some(mut snippet) = self.snippet_stack.pop() {
 9778            match bias {
 9779                Bias::Left => {
 9780                    if snippet.active_index > 0 {
 9781                        snippet.active_index -= 1;
 9782                    } else {
 9783                        self.snippet_stack.push(snippet);
 9784                        return false;
 9785                    }
 9786                }
 9787                Bias::Right => {
 9788                    if snippet.active_index + 1 < snippet.ranges.len() {
 9789                        snippet.active_index += 1;
 9790                    } else {
 9791                        self.snippet_stack.push(snippet);
 9792                        return false;
 9793                    }
 9794                }
 9795            }
 9796            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9797                self.change_selections(Default::default(), window, cx, |s| {
 9798                    // Reverse order so that the first range is the newest created selection.
 9799                    // Completions will use it and autoscroll will prioritize it.
 9800                    s.select_ranges(current_ranges.iter().rev().cloned())
 9801                });
 9802
 9803                if let Some(choices) = &snippet.choices[snippet.active_index]
 9804                    && let Some(selection) = current_ranges.first()
 9805                {
 9806                    self.show_snippet_choices(choices, selection.clone(), cx);
 9807                }
 9808
 9809                // If snippet state is not at the last tabstop, push it back on the stack
 9810                if snippet.active_index + 1 < snippet.ranges.len() {
 9811                    self.snippet_stack.push(snippet);
 9812                }
 9813                return true;
 9814            }
 9815        }
 9816
 9817        false
 9818    }
 9819
 9820    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9821        self.transact(window, cx, |this, window, cx| {
 9822            this.select_all(&SelectAll, window, cx);
 9823            this.insert("", window, cx);
 9824        });
 9825    }
 9826
 9827    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9828        if self.read_only(cx) {
 9829            return;
 9830        }
 9831        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9832        self.transact(window, cx, |this, window, cx| {
 9833            this.select_autoclose_pair(window, cx);
 9834
 9835            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9836
 9837            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9838            if !this.linked_edit_ranges.is_empty() {
 9839                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9840                let snapshot = this.buffer.read(cx).snapshot(cx);
 9841
 9842                for selection in selections.iter() {
 9843                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9844                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9845                    if selection_start.buffer_id != selection_end.buffer_id {
 9846                        continue;
 9847                    }
 9848                    if let Some(ranges) =
 9849                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9850                    {
 9851                        for (buffer, entries) in ranges {
 9852                            linked_ranges.entry(buffer).or_default().extend(entries);
 9853                        }
 9854                    }
 9855                }
 9856            }
 9857
 9858            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9859            for selection in &mut selections {
 9860                if selection.is_empty() {
 9861                    let old_head = selection.head();
 9862                    let mut new_head =
 9863                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9864                            .to_point(&display_map);
 9865                    if let Some((buffer, line_buffer_range)) = display_map
 9866                        .buffer_snapshot()
 9867                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9868                    {
 9869                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9870                        let indent_len = match indent_size.kind {
 9871                            IndentKind::Space => {
 9872                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9873                            }
 9874                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9875                        };
 9876                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9877                            let indent_len = indent_len.get();
 9878                            new_head = cmp::min(
 9879                                new_head,
 9880                                MultiBufferPoint::new(
 9881                                    old_head.row,
 9882                                    ((old_head.column - 1) / indent_len) * indent_len,
 9883                                ),
 9884                            );
 9885                        }
 9886                    }
 9887
 9888                    selection.set_head(new_head, SelectionGoal::None);
 9889                }
 9890            }
 9891
 9892            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9893            this.insert("", window, cx);
 9894            let empty_str: Arc<str> = Arc::from("");
 9895            for (buffer, edits) in linked_ranges {
 9896                let snapshot = buffer.read(cx).snapshot();
 9897                use text::ToPoint as TP;
 9898
 9899                let edits = edits
 9900                    .into_iter()
 9901                    .map(|range| {
 9902                        let end_point = TP::to_point(&range.end, &snapshot);
 9903                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9904
 9905                        if end_point == start_point {
 9906                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9907                                .saturating_sub(1);
 9908                            start_point =
 9909                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9910                        };
 9911
 9912                        (start_point..end_point, empty_str.clone())
 9913                    })
 9914                    .sorted_by_key(|(range, _)| range.start)
 9915                    .collect::<Vec<_>>();
 9916                buffer.update(cx, |this, cx| {
 9917                    this.edit(edits, None, cx);
 9918                })
 9919            }
 9920            this.refresh_edit_prediction(true, false, window, cx);
 9921            refresh_linked_ranges(this, window, cx);
 9922        });
 9923    }
 9924
 9925    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9926        if self.read_only(cx) {
 9927            return;
 9928        }
 9929        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9930        self.transact(window, cx, |this, window, cx| {
 9931            this.change_selections(Default::default(), window, cx, |s| {
 9932                s.move_with(|map, selection| {
 9933                    if selection.is_empty() {
 9934                        let cursor = movement::right(map, selection.head());
 9935                        selection.end = cursor;
 9936                        selection.reversed = true;
 9937                        selection.goal = SelectionGoal::None;
 9938                    }
 9939                })
 9940            });
 9941            this.insert("", window, cx);
 9942            this.refresh_edit_prediction(true, false, window, cx);
 9943        });
 9944    }
 9945
 9946    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9947        if self.mode.is_single_line() {
 9948            cx.propagate();
 9949            return;
 9950        }
 9951
 9952        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9953        if self.move_to_prev_snippet_tabstop(window, cx) {
 9954            return;
 9955        }
 9956        self.outdent(&Outdent, window, cx);
 9957    }
 9958
 9959    pub fn next_snippet_tabstop(
 9960        &mut self,
 9961        _: &NextSnippetTabstop,
 9962        window: &mut Window,
 9963        cx: &mut Context<Self>,
 9964    ) {
 9965        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
 9966            return;
 9967        }
 9968
 9969        if self.move_to_next_snippet_tabstop(window, cx) {
 9970            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9971            return;
 9972        }
 9973    }
 9974
 9975    pub fn previous_snippet_tabstop(
 9976        &mut self,
 9977        _: &PreviousSnippetTabstop,
 9978        window: &mut Window,
 9979        cx: &mut Context<Self>,
 9980    ) {
 9981        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
 9982            return;
 9983        }
 9984
 9985        if self.move_to_prev_snippet_tabstop(window, cx) {
 9986            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9987            return;
 9988        }
 9989    }
 9990
 9991    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9992        if self.mode.is_single_line() {
 9993            cx.propagate();
 9994            return;
 9995        }
 9996
 9997        if self.move_to_next_snippet_tabstop(window, cx) {
 9998            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9999            return;
10000        }
10001        if self.read_only(cx) {
10002            return;
10003        }
10004        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10005        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10006        let buffer = self.buffer.read(cx);
10007        let snapshot = buffer.snapshot(cx);
10008        let rows_iter = selections.iter().map(|s| s.head().row);
10009        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10010
10011        let has_some_cursor_in_whitespace = selections
10012            .iter()
10013            .filter(|selection| selection.is_empty())
10014            .any(|selection| {
10015                let cursor = selection.head();
10016                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10017                cursor.column < current_indent.len
10018            });
10019
10020        let mut edits = Vec::new();
10021        let mut prev_edited_row = 0;
10022        let mut row_delta = 0;
10023        for selection in &mut selections {
10024            if selection.start.row != prev_edited_row {
10025                row_delta = 0;
10026            }
10027            prev_edited_row = selection.end.row;
10028
10029            // If the selection is non-empty, then increase the indentation of the selected lines.
10030            if !selection.is_empty() {
10031                row_delta =
10032                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10033                continue;
10034            }
10035
10036            let cursor = selection.head();
10037            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10038            if let Some(suggested_indent) =
10039                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10040            {
10041                // Don't do anything if already at suggested indent
10042                // and there is any other cursor which is not
10043                if has_some_cursor_in_whitespace
10044                    && cursor.column == current_indent.len
10045                    && current_indent.len == suggested_indent.len
10046                {
10047                    continue;
10048                }
10049
10050                // Adjust line and move cursor to suggested indent
10051                // if cursor is not at suggested indent
10052                if cursor.column < suggested_indent.len
10053                    && cursor.column <= current_indent.len
10054                    && current_indent.len <= suggested_indent.len
10055                {
10056                    selection.start = Point::new(cursor.row, suggested_indent.len);
10057                    selection.end = selection.start;
10058                    if row_delta == 0 {
10059                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10060                            cursor.row,
10061                            current_indent,
10062                            suggested_indent,
10063                        ));
10064                        row_delta = suggested_indent.len - current_indent.len;
10065                    }
10066                    continue;
10067                }
10068
10069                // If current indent is more than suggested indent
10070                // only move cursor to current indent and skip indent
10071                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10072                    selection.start = Point::new(cursor.row, current_indent.len);
10073                    selection.end = selection.start;
10074                    continue;
10075                }
10076            }
10077
10078            // Otherwise, insert a hard or soft tab.
10079            let settings = buffer.language_settings_at(cursor, cx);
10080            let tab_size = if settings.hard_tabs {
10081                IndentSize::tab()
10082            } else {
10083                let tab_size = settings.tab_size.get();
10084                let indent_remainder = snapshot
10085                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10086                    .flat_map(str::chars)
10087                    .fold(row_delta % tab_size, |counter: u32, c| {
10088                        if c == '\t' {
10089                            0
10090                        } else {
10091                            (counter + 1) % tab_size
10092                        }
10093                    });
10094
10095                let chars_to_next_tab_stop = tab_size - indent_remainder;
10096                IndentSize::spaces(chars_to_next_tab_stop)
10097            };
10098            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10099            selection.end = selection.start;
10100            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10101            row_delta += tab_size.len;
10102        }
10103
10104        self.transact(window, cx, |this, window, cx| {
10105            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10106            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10107            this.refresh_edit_prediction(true, false, window, cx);
10108        });
10109    }
10110
10111    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10112        if self.read_only(cx) {
10113            return;
10114        }
10115        if self.mode.is_single_line() {
10116            cx.propagate();
10117            return;
10118        }
10119
10120        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10121        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10122        let mut prev_edited_row = 0;
10123        let mut row_delta = 0;
10124        let mut edits = Vec::new();
10125        let buffer = self.buffer.read(cx);
10126        let snapshot = buffer.snapshot(cx);
10127        for selection in &mut selections {
10128            if selection.start.row != prev_edited_row {
10129                row_delta = 0;
10130            }
10131            prev_edited_row = selection.end.row;
10132
10133            row_delta =
10134                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10135        }
10136
10137        self.transact(window, cx, |this, window, cx| {
10138            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10139            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10140        });
10141    }
10142
10143    fn indent_selection(
10144        buffer: &MultiBuffer,
10145        snapshot: &MultiBufferSnapshot,
10146        selection: &mut Selection<Point>,
10147        edits: &mut Vec<(Range<Point>, String)>,
10148        delta_for_start_row: u32,
10149        cx: &App,
10150    ) -> u32 {
10151        let settings = buffer.language_settings_at(selection.start, cx);
10152        let tab_size = settings.tab_size.get();
10153        let indent_kind = if settings.hard_tabs {
10154            IndentKind::Tab
10155        } else {
10156            IndentKind::Space
10157        };
10158        let mut start_row = selection.start.row;
10159        let mut end_row = selection.end.row + 1;
10160
10161        // If a selection ends at the beginning of a line, don't indent
10162        // that last line.
10163        if selection.end.column == 0 && selection.end.row > selection.start.row {
10164            end_row -= 1;
10165        }
10166
10167        // Avoid re-indenting a row that has already been indented by a
10168        // previous selection, but still update this selection's column
10169        // to reflect that indentation.
10170        if delta_for_start_row > 0 {
10171            start_row += 1;
10172            selection.start.column += delta_for_start_row;
10173            if selection.end.row == selection.start.row {
10174                selection.end.column += delta_for_start_row;
10175            }
10176        }
10177
10178        let mut delta_for_end_row = 0;
10179        let has_multiple_rows = start_row + 1 != end_row;
10180        for row in start_row..end_row {
10181            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10182            let indent_delta = match (current_indent.kind, indent_kind) {
10183                (IndentKind::Space, IndentKind::Space) => {
10184                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10185                    IndentSize::spaces(columns_to_next_tab_stop)
10186                }
10187                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10188                (_, IndentKind::Tab) => IndentSize::tab(),
10189            };
10190
10191            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10192                0
10193            } else {
10194                selection.start.column
10195            };
10196            let row_start = Point::new(row, start);
10197            edits.push((
10198                row_start..row_start,
10199                indent_delta.chars().collect::<String>(),
10200            ));
10201
10202            // Update this selection's endpoints to reflect the indentation.
10203            if row == selection.start.row {
10204                selection.start.column += indent_delta.len;
10205            }
10206            if row == selection.end.row {
10207                selection.end.column += indent_delta.len;
10208                delta_for_end_row = indent_delta.len;
10209            }
10210        }
10211
10212        if selection.start.row == selection.end.row {
10213            delta_for_start_row + delta_for_end_row
10214        } else {
10215            delta_for_end_row
10216        }
10217    }
10218
10219    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10220        if self.read_only(cx) {
10221            return;
10222        }
10223        if self.mode.is_single_line() {
10224            cx.propagate();
10225            return;
10226        }
10227
10228        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10229        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10230        let selections = self.selections.all::<Point>(&display_map);
10231        let mut deletion_ranges = Vec::new();
10232        let mut last_outdent = None;
10233        {
10234            let buffer = self.buffer.read(cx);
10235            let snapshot = buffer.snapshot(cx);
10236            for selection in &selections {
10237                let settings = buffer.language_settings_at(selection.start, cx);
10238                let tab_size = settings.tab_size.get();
10239                let mut rows = selection.spanned_rows(false, &display_map);
10240
10241                // Avoid re-outdenting a row that has already been outdented by a
10242                // previous selection.
10243                if let Some(last_row) = last_outdent
10244                    && last_row == rows.start
10245                {
10246                    rows.start = rows.start.next_row();
10247                }
10248                let has_multiple_rows = rows.len() > 1;
10249                for row in rows.iter_rows() {
10250                    let indent_size = snapshot.indent_size_for_line(row);
10251                    if indent_size.len > 0 {
10252                        let deletion_len = match indent_size.kind {
10253                            IndentKind::Space => {
10254                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10255                                if columns_to_prev_tab_stop == 0 {
10256                                    tab_size
10257                                } else {
10258                                    columns_to_prev_tab_stop
10259                                }
10260                            }
10261                            IndentKind::Tab => 1,
10262                        };
10263                        let start = if has_multiple_rows
10264                            || deletion_len > selection.start.column
10265                            || indent_size.len < selection.start.column
10266                        {
10267                            0
10268                        } else {
10269                            selection.start.column - deletion_len
10270                        };
10271                        deletion_ranges.push(
10272                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10273                        );
10274                        last_outdent = Some(row);
10275                    }
10276                }
10277            }
10278        }
10279
10280        self.transact(window, cx, |this, window, cx| {
10281            this.buffer.update(cx, |buffer, cx| {
10282                let empty_str: Arc<str> = Arc::default();
10283                buffer.edit(
10284                    deletion_ranges
10285                        .into_iter()
10286                        .map(|range| (range, empty_str.clone())),
10287                    None,
10288                    cx,
10289                );
10290            });
10291            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10292            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10293        });
10294    }
10295
10296    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10297        if self.read_only(cx) {
10298            return;
10299        }
10300        if self.mode.is_single_line() {
10301            cx.propagate();
10302            return;
10303        }
10304
10305        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10306        let selections = self
10307            .selections
10308            .all::<usize>(&self.display_snapshot(cx))
10309            .into_iter()
10310            .map(|s| s.range());
10311
10312        self.transact(window, cx, |this, window, cx| {
10313            this.buffer.update(cx, |buffer, cx| {
10314                buffer.autoindent_ranges(selections, cx);
10315            });
10316            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10317            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10318        });
10319    }
10320
10321    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10322        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10323        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10324        let selections = self.selections.all::<Point>(&display_map);
10325
10326        let mut new_cursors = Vec::new();
10327        let mut edit_ranges = Vec::new();
10328        let mut selections = selections.iter().peekable();
10329        while let Some(selection) = selections.next() {
10330            let mut rows = selection.spanned_rows(false, &display_map);
10331
10332            // Accumulate contiguous regions of rows that we want to delete.
10333            while let Some(next_selection) = selections.peek() {
10334                let next_rows = next_selection.spanned_rows(false, &display_map);
10335                if next_rows.start <= rows.end {
10336                    rows.end = next_rows.end;
10337                    selections.next().unwrap();
10338                } else {
10339                    break;
10340                }
10341            }
10342
10343            let buffer = display_map.buffer_snapshot();
10344            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10345            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10346                // If there's a line after the range, delete the \n from the end of the row range
10347                (
10348                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10349                    rows.end,
10350                )
10351            } else {
10352                // If there isn't a line after the range, delete the \n from the line before the
10353                // start of the row range
10354                edit_start = edit_start.saturating_sub(1);
10355                (buffer.len(), rows.start.previous_row())
10356            };
10357
10358            let text_layout_details = self.text_layout_details(window);
10359            let x = display_map.x_for_display_point(
10360                selection.head().to_display_point(&display_map),
10361                &text_layout_details,
10362            );
10363            let row = Point::new(target_row.0, 0)
10364                .to_display_point(&display_map)
10365                .row();
10366            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10367
10368            new_cursors.push((
10369                selection.id,
10370                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10371                SelectionGoal::None,
10372            ));
10373            edit_ranges.push(edit_start..edit_end);
10374        }
10375
10376        self.transact(window, cx, |this, window, cx| {
10377            let buffer = this.buffer.update(cx, |buffer, cx| {
10378                let empty_str: Arc<str> = Arc::default();
10379                buffer.edit(
10380                    edit_ranges
10381                        .into_iter()
10382                        .map(|range| (range, empty_str.clone())),
10383                    None,
10384                    cx,
10385                );
10386                buffer.snapshot(cx)
10387            });
10388            let new_selections = new_cursors
10389                .into_iter()
10390                .map(|(id, cursor, goal)| {
10391                    let cursor = cursor.to_point(&buffer);
10392                    Selection {
10393                        id,
10394                        start: cursor,
10395                        end: cursor,
10396                        reversed: false,
10397                        goal,
10398                    }
10399                })
10400                .collect();
10401
10402            this.change_selections(Default::default(), window, cx, |s| {
10403                s.select(new_selections);
10404            });
10405        });
10406    }
10407
10408    pub fn join_lines_impl(
10409        &mut self,
10410        insert_whitespace: bool,
10411        window: &mut Window,
10412        cx: &mut Context<Self>,
10413    ) {
10414        if self.read_only(cx) {
10415            return;
10416        }
10417        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10418        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10419            let start = MultiBufferRow(selection.start.row);
10420            // Treat single line selections as if they include the next line. Otherwise this action
10421            // would do nothing for single line selections individual cursors.
10422            let end = if selection.start.row == selection.end.row {
10423                MultiBufferRow(selection.start.row + 1)
10424            } else {
10425                MultiBufferRow(selection.end.row)
10426            };
10427
10428            if let Some(last_row_range) = row_ranges.last_mut()
10429                && start <= last_row_range.end
10430            {
10431                last_row_range.end = end;
10432                continue;
10433            }
10434            row_ranges.push(start..end);
10435        }
10436
10437        let snapshot = self.buffer.read(cx).snapshot(cx);
10438        let mut cursor_positions = Vec::new();
10439        for row_range in &row_ranges {
10440            let anchor = snapshot.anchor_before(Point::new(
10441                row_range.end.previous_row().0,
10442                snapshot.line_len(row_range.end.previous_row()),
10443            ));
10444            cursor_positions.push(anchor..anchor);
10445        }
10446
10447        self.transact(window, cx, |this, window, cx| {
10448            for row_range in row_ranges.into_iter().rev() {
10449                for row in row_range.iter_rows().rev() {
10450                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10451                    let next_line_row = row.next_row();
10452                    let indent = snapshot.indent_size_for_line(next_line_row);
10453                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10454
10455                    let replace =
10456                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10457                            " "
10458                        } else {
10459                            ""
10460                        };
10461
10462                    this.buffer.update(cx, |buffer, cx| {
10463                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10464                    });
10465                }
10466            }
10467
10468            this.change_selections(Default::default(), window, cx, |s| {
10469                s.select_anchor_ranges(cursor_positions)
10470            });
10471        });
10472    }
10473
10474    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10475        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10476        self.join_lines_impl(true, window, cx);
10477    }
10478
10479    pub fn sort_lines_case_sensitive(
10480        &mut self,
10481        _: &SortLinesCaseSensitive,
10482        window: &mut Window,
10483        cx: &mut Context<Self>,
10484    ) {
10485        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10486    }
10487
10488    pub fn sort_lines_by_length(
10489        &mut self,
10490        _: &SortLinesByLength,
10491        window: &mut Window,
10492        cx: &mut Context<Self>,
10493    ) {
10494        self.manipulate_immutable_lines(window, cx, |lines| {
10495            lines.sort_by_key(|&line| line.chars().count())
10496        })
10497    }
10498
10499    pub fn sort_lines_case_insensitive(
10500        &mut self,
10501        _: &SortLinesCaseInsensitive,
10502        window: &mut Window,
10503        cx: &mut Context<Self>,
10504    ) {
10505        self.manipulate_immutable_lines(window, cx, |lines| {
10506            lines.sort_by_key(|line| line.to_lowercase())
10507        })
10508    }
10509
10510    pub fn unique_lines_case_insensitive(
10511        &mut self,
10512        _: &UniqueLinesCaseInsensitive,
10513        window: &mut Window,
10514        cx: &mut Context<Self>,
10515    ) {
10516        self.manipulate_immutable_lines(window, cx, |lines| {
10517            let mut seen = HashSet::default();
10518            lines.retain(|line| seen.insert(line.to_lowercase()));
10519        })
10520    }
10521
10522    pub fn unique_lines_case_sensitive(
10523        &mut self,
10524        _: &UniqueLinesCaseSensitive,
10525        window: &mut Window,
10526        cx: &mut Context<Self>,
10527    ) {
10528        self.manipulate_immutable_lines(window, cx, |lines| {
10529            let mut seen = HashSet::default();
10530            lines.retain(|line| seen.insert(*line));
10531        })
10532    }
10533
10534    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10535        let snapshot = self.buffer.read(cx).snapshot(cx);
10536        for selection in self.selections.disjoint_anchors_arc().iter() {
10537            if snapshot
10538                .language_at(selection.start)
10539                .and_then(|lang| lang.config().wrap_characters.as_ref())
10540                .is_some()
10541            {
10542                return true;
10543            }
10544        }
10545        false
10546    }
10547
10548    fn wrap_selections_in_tag(
10549        &mut self,
10550        _: &WrapSelectionsInTag,
10551        window: &mut Window,
10552        cx: &mut Context<Self>,
10553    ) {
10554        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10555
10556        let snapshot = self.buffer.read(cx).snapshot(cx);
10557
10558        let mut edits = Vec::new();
10559        let mut boundaries = Vec::new();
10560
10561        for selection in self
10562            .selections
10563            .all_adjusted(&self.display_snapshot(cx))
10564            .iter()
10565        {
10566            let Some(wrap_config) = snapshot
10567                .language_at(selection.start)
10568                .and_then(|lang| lang.config().wrap_characters.clone())
10569            else {
10570                continue;
10571            };
10572
10573            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10574            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10575
10576            let start_before = snapshot.anchor_before(selection.start);
10577            let end_after = snapshot.anchor_after(selection.end);
10578
10579            edits.push((start_before..start_before, open_tag));
10580            edits.push((end_after..end_after, close_tag));
10581
10582            boundaries.push((
10583                start_before,
10584                end_after,
10585                wrap_config.start_prefix.len(),
10586                wrap_config.end_suffix.len(),
10587            ));
10588        }
10589
10590        if edits.is_empty() {
10591            return;
10592        }
10593
10594        self.transact(window, cx, |this, window, cx| {
10595            let buffer = this.buffer.update(cx, |buffer, cx| {
10596                buffer.edit(edits, None, cx);
10597                buffer.snapshot(cx)
10598            });
10599
10600            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10601            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10602                boundaries.into_iter()
10603            {
10604                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10605                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10606                new_selections.push(open_offset..open_offset);
10607                new_selections.push(close_offset..close_offset);
10608            }
10609
10610            this.change_selections(Default::default(), window, cx, |s| {
10611                s.select_ranges(new_selections);
10612            });
10613
10614            this.request_autoscroll(Autoscroll::fit(), cx);
10615        });
10616    }
10617
10618    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10619        let Some(project) = self.project.clone() else {
10620            return;
10621        };
10622        self.reload(project, window, cx)
10623            .detach_and_notify_err(window, cx);
10624    }
10625
10626    pub fn restore_file(
10627        &mut self,
10628        _: &::git::RestoreFile,
10629        window: &mut Window,
10630        cx: &mut Context<Self>,
10631    ) {
10632        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10633        let mut buffer_ids = HashSet::default();
10634        let snapshot = self.buffer().read(cx).snapshot(cx);
10635        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10636            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10637        }
10638
10639        let buffer = self.buffer().read(cx);
10640        let ranges = buffer_ids
10641            .into_iter()
10642            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10643            .collect::<Vec<_>>();
10644
10645        self.restore_hunks_in_ranges(ranges, window, cx);
10646    }
10647
10648    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10649        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10650        let selections = self
10651            .selections
10652            .all(&self.display_snapshot(cx))
10653            .into_iter()
10654            .map(|s| s.range())
10655            .collect();
10656        self.restore_hunks_in_ranges(selections, window, cx);
10657    }
10658
10659    pub fn restore_hunks_in_ranges(
10660        &mut self,
10661        ranges: Vec<Range<Point>>,
10662        window: &mut Window,
10663        cx: &mut Context<Editor>,
10664    ) {
10665        let mut revert_changes = HashMap::default();
10666        let chunk_by = self
10667            .snapshot(window, cx)
10668            .hunks_for_ranges(ranges)
10669            .into_iter()
10670            .chunk_by(|hunk| hunk.buffer_id);
10671        for (buffer_id, hunks) in &chunk_by {
10672            let hunks = hunks.collect::<Vec<_>>();
10673            for hunk in &hunks {
10674                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10675            }
10676            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10677        }
10678        drop(chunk_by);
10679        if !revert_changes.is_empty() {
10680            self.transact(window, cx, |editor, window, cx| {
10681                editor.restore(revert_changes, window, cx);
10682            });
10683        }
10684    }
10685
10686    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10687        if let Some(status) = self
10688            .addons
10689            .iter()
10690            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10691        {
10692            return Some(status);
10693        }
10694        self.project
10695            .as_ref()?
10696            .read(cx)
10697            .status_for_buffer_id(buffer_id, cx)
10698    }
10699
10700    pub fn open_active_item_in_terminal(
10701        &mut self,
10702        _: &OpenInTerminal,
10703        window: &mut Window,
10704        cx: &mut Context<Self>,
10705    ) {
10706        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10707            let project_path = buffer.read(cx).project_path(cx)?;
10708            let project = self.project()?.read(cx);
10709            let entry = project.entry_for_path(&project_path, cx)?;
10710            let parent = match &entry.canonical_path {
10711                Some(canonical_path) => canonical_path.to_path_buf(),
10712                None => project.absolute_path(&project_path, cx)?,
10713            }
10714            .parent()?
10715            .to_path_buf();
10716            Some(parent)
10717        }) {
10718            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10719        }
10720    }
10721
10722    fn set_breakpoint_context_menu(
10723        &mut self,
10724        display_row: DisplayRow,
10725        position: Option<Anchor>,
10726        clicked_point: gpui::Point<Pixels>,
10727        window: &mut Window,
10728        cx: &mut Context<Self>,
10729    ) {
10730        let source = self
10731            .buffer
10732            .read(cx)
10733            .snapshot(cx)
10734            .anchor_before(Point::new(display_row.0, 0u32));
10735
10736        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10737
10738        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10739            self,
10740            source,
10741            clicked_point,
10742            context_menu,
10743            window,
10744            cx,
10745        );
10746    }
10747
10748    fn add_edit_breakpoint_block(
10749        &mut self,
10750        anchor: Anchor,
10751        breakpoint: &Breakpoint,
10752        edit_action: BreakpointPromptEditAction,
10753        window: &mut Window,
10754        cx: &mut Context<Self>,
10755    ) {
10756        let weak_editor = cx.weak_entity();
10757        let bp_prompt = cx.new(|cx| {
10758            BreakpointPromptEditor::new(
10759                weak_editor,
10760                anchor,
10761                breakpoint.clone(),
10762                edit_action,
10763                window,
10764                cx,
10765            )
10766        });
10767
10768        let height = bp_prompt.update(cx, |this, cx| {
10769            this.prompt
10770                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10771        });
10772        let cloned_prompt = bp_prompt.clone();
10773        let blocks = vec![BlockProperties {
10774            style: BlockStyle::Sticky,
10775            placement: BlockPlacement::Above(anchor),
10776            height: Some(height),
10777            render: Arc::new(move |cx| {
10778                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10779                cloned_prompt.clone().into_any_element()
10780            }),
10781            priority: 0,
10782        }];
10783
10784        let focus_handle = bp_prompt.focus_handle(cx);
10785        window.focus(&focus_handle);
10786
10787        let block_ids = self.insert_blocks(blocks, None, cx);
10788        bp_prompt.update(cx, |prompt, _| {
10789            prompt.add_block_ids(block_ids);
10790        });
10791    }
10792
10793    pub(crate) fn breakpoint_at_row(
10794        &self,
10795        row: u32,
10796        window: &mut Window,
10797        cx: &mut Context<Self>,
10798    ) -> Option<(Anchor, Breakpoint)> {
10799        let snapshot = self.snapshot(window, cx);
10800        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10801
10802        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10803    }
10804
10805    pub(crate) fn breakpoint_at_anchor(
10806        &self,
10807        breakpoint_position: Anchor,
10808        snapshot: &EditorSnapshot,
10809        cx: &mut Context<Self>,
10810    ) -> Option<(Anchor, Breakpoint)> {
10811        let buffer = self
10812            .buffer
10813            .read(cx)
10814            .buffer_for_anchor(breakpoint_position, cx)?;
10815
10816        let enclosing_excerpt = breakpoint_position.excerpt_id;
10817        let buffer_snapshot = buffer.read(cx).snapshot();
10818
10819        let row = buffer_snapshot
10820            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10821            .row;
10822
10823        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10824        let anchor_end = snapshot
10825            .buffer_snapshot()
10826            .anchor_after(Point::new(row, line_len));
10827
10828        self.breakpoint_store
10829            .as_ref()?
10830            .read_with(cx, |breakpoint_store, cx| {
10831                breakpoint_store
10832                    .breakpoints(
10833                        &buffer,
10834                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10835                        &buffer_snapshot,
10836                        cx,
10837                    )
10838                    .next()
10839                    .and_then(|(bp, _)| {
10840                        let breakpoint_row = buffer_snapshot
10841                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10842                            .row;
10843
10844                        if breakpoint_row == row {
10845                            snapshot
10846                                .buffer_snapshot()
10847                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10848                                .map(|position| (position, bp.bp.clone()))
10849                        } else {
10850                            None
10851                        }
10852                    })
10853            })
10854    }
10855
10856    pub fn edit_log_breakpoint(
10857        &mut self,
10858        _: &EditLogBreakpoint,
10859        window: &mut Window,
10860        cx: &mut Context<Self>,
10861    ) {
10862        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10863            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10864                message: None,
10865                state: BreakpointState::Enabled,
10866                condition: None,
10867                hit_condition: None,
10868            });
10869
10870            self.add_edit_breakpoint_block(
10871                anchor,
10872                &breakpoint,
10873                BreakpointPromptEditAction::Log,
10874                window,
10875                cx,
10876            );
10877        }
10878    }
10879
10880    fn breakpoints_at_cursors(
10881        &self,
10882        window: &mut Window,
10883        cx: &mut Context<Self>,
10884    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10885        let snapshot = self.snapshot(window, cx);
10886        let cursors = self
10887            .selections
10888            .disjoint_anchors_arc()
10889            .iter()
10890            .map(|selection| {
10891                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10892
10893                let breakpoint_position = self
10894                    .breakpoint_at_row(cursor_position.row, window, cx)
10895                    .map(|bp| bp.0)
10896                    .unwrap_or_else(|| {
10897                        snapshot
10898                            .display_snapshot
10899                            .buffer_snapshot()
10900                            .anchor_after(Point::new(cursor_position.row, 0))
10901                    });
10902
10903                let breakpoint = self
10904                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10905                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10906
10907                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10908            })
10909            // 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.
10910            .collect::<HashMap<Anchor, _>>();
10911
10912        cursors.into_iter().collect()
10913    }
10914
10915    pub fn enable_breakpoint(
10916        &mut self,
10917        _: &crate::actions::EnableBreakpoint,
10918        window: &mut Window,
10919        cx: &mut Context<Self>,
10920    ) {
10921        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10922            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10923                continue;
10924            };
10925            self.edit_breakpoint_at_anchor(
10926                anchor,
10927                breakpoint,
10928                BreakpointEditAction::InvertState,
10929                cx,
10930            );
10931        }
10932    }
10933
10934    pub fn disable_breakpoint(
10935        &mut self,
10936        _: &crate::actions::DisableBreakpoint,
10937        window: &mut Window,
10938        cx: &mut Context<Self>,
10939    ) {
10940        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10941            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10942                continue;
10943            };
10944            self.edit_breakpoint_at_anchor(
10945                anchor,
10946                breakpoint,
10947                BreakpointEditAction::InvertState,
10948                cx,
10949            );
10950        }
10951    }
10952
10953    pub fn toggle_breakpoint(
10954        &mut self,
10955        _: &crate::actions::ToggleBreakpoint,
10956        window: &mut Window,
10957        cx: &mut Context<Self>,
10958    ) {
10959        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10960            if let Some(breakpoint) = breakpoint {
10961                self.edit_breakpoint_at_anchor(
10962                    anchor,
10963                    breakpoint,
10964                    BreakpointEditAction::Toggle,
10965                    cx,
10966                );
10967            } else {
10968                self.edit_breakpoint_at_anchor(
10969                    anchor,
10970                    Breakpoint::new_standard(),
10971                    BreakpointEditAction::Toggle,
10972                    cx,
10973                );
10974            }
10975        }
10976    }
10977
10978    pub fn edit_breakpoint_at_anchor(
10979        &mut self,
10980        breakpoint_position: Anchor,
10981        breakpoint: Breakpoint,
10982        edit_action: BreakpointEditAction,
10983        cx: &mut Context<Self>,
10984    ) {
10985        let Some(breakpoint_store) = &self.breakpoint_store else {
10986            return;
10987        };
10988
10989        let Some(buffer) = self
10990            .buffer
10991            .read(cx)
10992            .buffer_for_anchor(breakpoint_position, cx)
10993        else {
10994            return;
10995        };
10996
10997        breakpoint_store.update(cx, |breakpoint_store, cx| {
10998            breakpoint_store.toggle_breakpoint(
10999                buffer,
11000                BreakpointWithPosition {
11001                    position: breakpoint_position.text_anchor,
11002                    bp: breakpoint,
11003                },
11004                edit_action,
11005                cx,
11006            );
11007        });
11008
11009        cx.notify();
11010    }
11011
11012    #[cfg(any(test, feature = "test-support"))]
11013    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11014        self.breakpoint_store.clone()
11015    }
11016
11017    pub fn prepare_restore_change(
11018        &self,
11019        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11020        hunk: &MultiBufferDiffHunk,
11021        cx: &mut App,
11022    ) -> Option<()> {
11023        if hunk.is_created_file() {
11024            return None;
11025        }
11026        let buffer = self.buffer.read(cx);
11027        let diff = buffer.diff_for(hunk.buffer_id)?;
11028        let buffer = buffer.buffer(hunk.buffer_id)?;
11029        let buffer = buffer.read(cx);
11030        let original_text = diff
11031            .read(cx)
11032            .base_text()
11033            .as_rope()
11034            .slice(hunk.diff_base_byte_range.clone());
11035        let buffer_snapshot = buffer.snapshot();
11036        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11037        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11038            probe
11039                .0
11040                .start
11041                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11042                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11043        }) {
11044            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11045            Some(())
11046        } else {
11047            None
11048        }
11049    }
11050
11051    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11052        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11053    }
11054
11055    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11056        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11057    }
11058
11059    fn manipulate_lines<M>(
11060        &mut self,
11061        window: &mut Window,
11062        cx: &mut Context<Self>,
11063        mut manipulate: M,
11064    ) where
11065        M: FnMut(&str) -> LineManipulationResult,
11066    {
11067        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11068
11069        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11070        let buffer = self.buffer.read(cx).snapshot(cx);
11071
11072        let mut edits = Vec::new();
11073
11074        let selections = self.selections.all::<Point>(&display_map);
11075        let mut selections = selections.iter().peekable();
11076        let mut contiguous_row_selections = Vec::new();
11077        let mut new_selections = Vec::new();
11078        let mut added_lines = 0;
11079        let mut removed_lines = 0;
11080
11081        while let Some(selection) = selections.next() {
11082            let (start_row, end_row) = consume_contiguous_rows(
11083                &mut contiguous_row_selections,
11084                selection,
11085                &display_map,
11086                &mut selections,
11087            );
11088
11089            let start_point = Point::new(start_row.0, 0);
11090            let end_point = Point::new(
11091                end_row.previous_row().0,
11092                buffer.line_len(end_row.previous_row()),
11093            );
11094            let text = buffer
11095                .text_for_range(start_point..end_point)
11096                .collect::<String>();
11097
11098            let LineManipulationResult {
11099                new_text,
11100                line_count_before,
11101                line_count_after,
11102            } = manipulate(&text);
11103
11104            edits.push((start_point..end_point, new_text));
11105
11106            // Selections must change based on added and removed line count
11107            let start_row =
11108                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11109            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11110            new_selections.push(Selection {
11111                id: selection.id,
11112                start: start_row,
11113                end: end_row,
11114                goal: SelectionGoal::None,
11115                reversed: selection.reversed,
11116            });
11117
11118            if line_count_after > line_count_before {
11119                added_lines += line_count_after - line_count_before;
11120            } else if line_count_before > line_count_after {
11121                removed_lines += line_count_before - line_count_after;
11122            }
11123        }
11124
11125        self.transact(window, cx, |this, window, cx| {
11126            let buffer = this.buffer.update(cx, |buffer, cx| {
11127                buffer.edit(edits, None, cx);
11128                buffer.snapshot(cx)
11129            });
11130
11131            // Recalculate offsets on newly edited buffer
11132            let new_selections = new_selections
11133                .iter()
11134                .map(|s| {
11135                    let start_point = Point::new(s.start.0, 0);
11136                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11137                    Selection {
11138                        id: s.id,
11139                        start: buffer.point_to_offset(start_point),
11140                        end: buffer.point_to_offset(end_point),
11141                        goal: s.goal,
11142                        reversed: s.reversed,
11143                    }
11144                })
11145                .collect();
11146
11147            this.change_selections(Default::default(), window, cx, |s| {
11148                s.select(new_selections);
11149            });
11150
11151            this.request_autoscroll(Autoscroll::fit(), cx);
11152        });
11153    }
11154
11155    fn manipulate_immutable_lines<Fn>(
11156        &mut self,
11157        window: &mut Window,
11158        cx: &mut Context<Self>,
11159        mut callback: Fn,
11160    ) where
11161        Fn: FnMut(&mut Vec<&str>),
11162    {
11163        self.manipulate_lines(window, cx, |text| {
11164            let mut lines: Vec<&str> = text.split('\n').collect();
11165            let line_count_before = lines.len();
11166
11167            callback(&mut lines);
11168
11169            LineManipulationResult {
11170                new_text: lines.join("\n"),
11171                line_count_before,
11172                line_count_after: lines.len(),
11173            }
11174        });
11175    }
11176
11177    fn manipulate_mutable_lines<Fn>(
11178        &mut self,
11179        window: &mut Window,
11180        cx: &mut Context<Self>,
11181        mut callback: Fn,
11182    ) where
11183        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11184    {
11185        self.manipulate_lines(window, cx, |text| {
11186            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11187            let line_count_before = lines.len();
11188
11189            callback(&mut lines);
11190
11191            LineManipulationResult {
11192                new_text: lines.join("\n"),
11193                line_count_before,
11194                line_count_after: lines.len(),
11195            }
11196        });
11197    }
11198
11199    pub fn convert_indentation_to_spaces(
11200        &mut self,
11201        _: &ConvertIndentationToSpaces,
11202        window: &mut Window,
11203        cx: &mut Context<Self>,
11204    ) {
11205        let settings = self.buffer.read(cx).language_settings(cx);
11206        let tab_size = settings.tab_size.get() as usize;
11207
11208        self.manipulate_mutable_lines(window, cx, |lines| {
11209            // Allocates a reasonably sized scratch buffer once for the whole loop
11210            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11211            // Avoids recomputing spaces that could be inserted many times
11212            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11213                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11214                .collect();
11215
11216            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11217                let mut chars = line.as_ref().chars();
11218                let mut col = 0;
11219                let mut changed = false;
11220
11221                for ch in chars.by_ref() {
11222                    match ch {
11223                        ' ' => {
11224                            reindented_line.push(' ');
11225                            col += 1;
11226                        }
11227                        '\t' => {
11228                            // \t are converted to spaces depending on the current column
11229                            let spaces_len = tab_size - (col % tab_size);
11230                            reindented_line.extend(&space_cache[spaces_len - 1]);
11231                            col += spaces_len;
11232                            changed = true;
11233                        }
11234                        _ => {
11235                            // If we dont append before break, the character is consumed
11236                            reindented_line.push(ch);
11237                            break;
11238                        }
11239                    }
11240                }
11241
11242                if !changed {
11243                    reindented_line.clear();
11244                    continue;
11245                }
11246                // Append the rest of the line and replace old reference with new one
11247                reindented_line.extend(chars);
11248                *line = Cow::Owned(reindented_line.clone());
11249                reindented_line.clear();
11250            }
11251        });
11252    }
11253
11254    pub fn convert_indentation_to_tabs(
11255        &mut self,
11256        _: &ConvertIndentationToTabs,
11257        window: &mut Window,
11258        cx: &mut Context<Self>,
11259    ) {
11260        let settings = self.buffer.read(cx).language_settings(cx);
11261        let tab_size = settings.tab_size.get() as usize;
11262
11263        self.manipulate_mutable_lines(window, cx, |lines| {
11264            // Allocates a reasonably sized buffer once for the whole loop
11265            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11266            // Avoids recomputing spaces that could be inserted many times
11267            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11268                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11269                .collect();
11270
11271            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11272                let mut chars = line.chars();
11273                let mut spaces_count = 0;
11274                let mut first_non_indent_char = None;
11275                let mut changed = false;
11276
11277                for ch in chars.by_ref() {
11278                    match ch {
11279                        ' ' => {
11280                            // Keep track of spaces. Append \t when we reach tab_size
11281                            spaces_count += 1;
11282                            changed = true;
11283                            if spaces_count == tab_size {
11284                                reindented_line.push('\t');
11285                                spaces_count = 0;
11286                            }
11287                        }
11288                        '\t' => {
11289                            reindented_line.push('\t');
11290                            spaces_count = 0;
11291                        }
11292                        _ => {
11293                            // Dont append it yet, we might have remaining spaces
11294                            first_non_indent_char = Some(ch);
11295                            break;
11296                        }
11297                    }
11298                }
11299
11300                if !changed {
11301                    reindented_line.clear();
11302                    continue;
11303                }
11304                // Remaining spaces that didn't make a full tab stop
11305                if spaces_count > 0 {
11306                    reindented_line.extend(&space_cache[spaces_count - 1]);
11307                }
11308                // If we consume an extra character that was not indentation, add it back
11309                if let Some(extra_char) = first_non_indent_char {
11310                    reindented_line.push(extra_char);
11311                }
11312                // Append the rest of the line and replace old reference with new one
11313                reindented_line.extend(chars);
11314                *line = Cow::Owned(reindented_line.clone());
11315                reindented_line.clear();
11316            }
11317        });
11318    }
11319
11320    pub fn convert_to_upper_case(
11321        &mut self,
11322        _: &ConvertToUpperCase,
11323        window: &mut Window,
11324        cx: &mut Context<Self>,
11325    ) {
11326        self.manipulate_text(window, cx, |text| text.to_uppercase())
11327    }
11328
11329    pub fn convert_to_lower_case(
11330        &mut self,
11331        _: &ConvertToLowerCase,
11332        window: &mut Window,
11333        cx: &mut Context<Self>,
11334    ) {
11335        self.manipulate_text(window, cx, |text| text.to_lowercase())
11336    }
11337
11338    pub fn convert_to_title_case(
11339        &mut self,
11340        _: &ConvertToTitleCase,
11341        window: &mut Window,
11342        cx: &mut Context<Self>,
11343    ) {
11344        self.manipulate_text(window, cx, |text| {
11345            text.split('\n')
11346                .map(|line| line.to_case(Case::Title))
11347                .join("\n")
11348        })
11349    }
11350
11351    pub fn convert_to_snake_case(
11352        &mut self,
11353        _: &ConvertToSnakeCase,
11354        window: &mut Window,
11355        cx: &mut Context<Self>,
11356    ) {
11357        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11358    }
11359
11360    pub fn convert_to_kebab_case(
11361        &mut self,
11362        _: &ConvertToKebabCase,
11363        window: &mut Window,
11364        cx: &mut Context<Self>,
11365    ) {
11366        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11367    }
11368
11369    pub fn convert_to_upper_camel_case(
11370        &mut self,
11371        _: &ConvertToUpperCamelCase,
11372        window: &mut Window,
11373        cx: &mut Context<Self>,
11374    ) {
11375        self.manipulate_text(window, cx, |text| {
11376            text.split('\n')
11377                .map(|line| line.to_case(Case::UpperCamel))
11378                .join("\n")
11379        })
11380    }
11381
11382    pub fn convert_to_lower_camel_case(
11383        &mut self,
11384        _: &ConvertToLowerCamelCase,
11385        window: &mut Window,
11386        cx: &mut Context<Self>,
11387    ) {
11388        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11389    }
11390
11391    pub fn convert_to_opposite_case(
11392        &mut self,
11393        _: &ConvertToOppositeCase,
11394        window: &mut Window,
11395        cx: &mut Context<Self>,
11396    ) {
11397        self.manipulate_text(window, cx, |text| {
11398            text.chars()
11399                .fold(String::with_capacity(text.len()), |mut t, c| {
11400                    if c.is_uppercase() {
11401                        t.extend(c.to_lowercase());
11402                    } else {
11403                        t.extend(c.to_uppercase());
11404                    }
11405                    t
11406                })
11407        })
11408    }
11409
11410    pub fn convert_to_sentence_case(
11411        &mut self,
11412        _: &ConvertToSentenceCase,
11413        window: &mut Window,
11414        cx: &mut Context<Self>,
11415    ) {
11416        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11417    }
11418
11419    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11420        self.manipulate_text(window, cx, |text| {
11421            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11422            if has_upper_case_characters {
11423                text.to_lowercase()
11424            } else {
11425                text.to_uppercase()
11426            }
11427        })
11428    }
11429
11430    pub fn convert_to_rot13(
11431        &mut self,
11432        _: &ConvertToRot13,
11433        window: &mut Window,
11434        cx: &mut Context<Self>,
11435    ) {
11436        self.manipulate_text(window, cx, |text| {
11437            text.chars()
11438                .map(|c| match c {
11439                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11440                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11441                    _ => c,
11442                })
11443                .collect()
11444        })
11445    }
11446
11447    pub fn convert_to_rot47(
11448        &mut self,
11449        _: &ConvertToRot47,
11450        window: &mut Window,
11451        cx: &mut Context<Self>,
11452    ) {
11453        self.manipulate_text(window, cx, |text| {
11454            text.chars()
11455                .map(|c| {
11456                    let code_point = c as u32;
11457                    if code_point >= 33 && code_point <= 126 {
11458                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11459                    }
11460                    c
11461                })
11462                .collect()
11463        })
11464    }
11465
11466    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11467    where
11468        Fn: FnMut(&str) -> String,
11469    {
11470        let buffer = self.buffer.read(cx).snapshot(cx);
11471
11472        let mut new_selections = Vec::new();
11473        let mut edits = Vec::new();
11474        let mut selection_adjustment = 0i32;
11475
11476        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11477            let selection_is_empty = selection.is_empty();
11478
11479            let (start, end) = if selection_is_empty {
11480                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11481                (word_range.start, word_range.end)
11482            } else {
11483                (
11484                    buffer.point_to_offset(selection.start),
11485                    buffer.point_to_offset(selection.end),
11486                )
11487            };
11488
11489            let text = buffer.text_for_range(start..end).collect::<String>();
11490            let old_length = text.len() as i32;
11491            let text = callback(&text);
11492
11493            new_selections.push(Selection {
11494                start: (start as i32 - selection_adjustment) as usize,
11495                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11496                goal: SelectionGoal::None,
11497                id: selection.id,
11498                reversed: selection.reversed,
11499            });
11500
11501            selection_adjustment += old_length - text.len() as i32;
11502
11503            edits.push((start..end, text));
11504        }
11505
11506        self.transact(window, cx, |this, window, cx| {
11507            this.buffer.update(cx, |buffer, cx| {
11508                buffer.edit(edits, None, cx);
11509            });
11510
11511            this.change_selections(Default::default(), window, cx, |s| {
11512                s.select(new_selections);
11513            });
11514
11515            this.request_autoscroll(Autoscroll::fit(), cx);
11516        });
11517    }
11518
11519    pub fn move_selection_on_drop(
11520        &mut self,
11521        selection: &Selection<Anchor>,
11522        target: DisplayPoint,
11523        is_cut: bool,
11524        window: &mut Window,
11525        cx: &mut Context<Self>,
11526    ) {
11527        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11528        let buffer = display_map.buffer_snapshot();
11529        let mut edits = Vec::new();
11530        let insert_point = display_map
11531            .clip_point(target, Bias::Left)
11532            .to_point(&display_map);
11533        let text = buffer
11534            .text_for_range(selection.start..selection.end)
11535            .collect::<String>();
11536        if is_cut {
11537            edits.push(((selection.start..selection.end), String::new()));
11538        }
11539        let insert_anchor = buffer.anchor_before(insert_point);
11540        edits.push(((insert_anchor..insert_anchor), text));
11541        let last_edit_start = insert_anchor.bias_left(buffer);
11542        let last_edit_end = insert_anchor.bias_right(buffer);
11543        self.transact(window, cx, |this, window, cx| {
11544            this.buffer.update(cx, |buffer, cx| {
11545                buffer.edit(edits, None, cx);
11546            });
11547            this.change_selections(Default::default(), window, cx, |s| {
11548                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11549            });
11550        });
11551    }
11552
11553    pub fn clear_selection_drag_state(&mut self) {
11554        self.selection_drag_state = SelectionDragState::None;
11555    }
11556
11557    pub fn duplicate(
11558        &mut self,
11559        upwards: bool,
11560        whole_lines: bool,
11561        window: &mut Window,
11562        cx: &mut Context<Self>,
11563    ) {
11564        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11565
11566        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11567        let buffer = display_map.buffer_snapshot();
11568        let selections = self.selections.all::<Point>(&display_map);
11569
11570        let mut edits = Vec::new();
11571        let mut selections_iter = selections.iter().peekable();
11572        while let Some(selection) = selections_iter.next() {
11573            let mut rows = selection.spanned_rows(false, &display_map);
11574            // duplicate line-wise
11575            if whole_lines || selection.start == selection.end {
11576                // Avoid duplicating the same lines twice.
11577                while let Some(next_selection) = selections_iter.peek() {
11578                    let next_rows = next_selection.spanned_rows(false, &display_map);
11579                    if next_rows.start < rows.end {
11580                        rows.end = next_rows.end;
11581                        selections_iter.next().unwrap();
11582                    } else {
11583                        break;
11584                    }
11585                }
11586
11587                // Copy the text from the selected row region and splice it either at the start
11588                // or end of the region.
11589                let start = Point::new(rows.start.0, 0);
11590                let end = Point::new(
11591                    rows.end.previous_row().0,
11592                    buffer.line_len(rows.end.previous_row()),
11593                );
11594
11595                let mut text = buffer.text_for_range(start..end).collect::<String>();
11596
11597                let insert_location = if upwards {
11598                    // When duplicating upward, we need to insert before the current line.
11599                    // If we're on the last line and it doesn't end with a newline,
11600                    // we need to add a newline before the duplicated content.
11601                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11602                        && buffer.max_point().column > 0
11603                        && !text.ends_with('\n');
11604
11605                    if needs_leading_newline {
11606                        text.insert(0, '\n');
11607                        end
11608                    } else {
11609                        text.push('\n');
11610                        Point::new(rows.start.0, 0)
11611                    }
11612                } else {
11613                    text.push('\n');
11614                    start
11615                };
11616                edits.push((insert_location..insert_location, text));
11617            } else {
11618                // duplicate character-wise
11619                let start = selection.start;
11620                let end = selection.end;
11621                let text = buffer.text_for_range(start..end).collect::<String>();
11622                edits.push((selection.end..selection.end, text));
11623            }
11624        }
11625
11626        self.transact(window, cx, |this, window, cx| {
11627            this.buffer.update(cx, |buffer, cx| {
11628                buffer.edit(edits, None, cx);
11629            });
11630
11631            // When duplicating upward with whole lines, move the cursor to the duplicated line
11632            if upwards && whole_lines {
11633                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11634
11635                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11636                    let mut new_ranges = Vec::new();
11637                    let selections = s.all::<Point>(&display_map);
11638                    let mut selections_iter = selections.iter().peekable();
11639
11640                    while let Some(first_selection) = selections_iter.next() {
11641                        // Group contiguous selections together to find the total row span
11642                        let mut group_selections = vec![first_selection];
11643                        let mut rows = first_selection.spanned_rows(false, &display_map);
11644
11645                        while let Some(next_selection) = selections_iter.peek() {
11646                            let next_rows = next_selection.spanned_rows(false, &display_map);
11647                            if next_rows.start < rows.end {
11648                                rows.end = next_rows.end;
11649                                group_selections.push(selections_iter.next().unwrap());
11650                            } else {
11651                                break;
11652                            }
11653                        }
11654
11655                        let row_count = rows.end.0 - rows.start.0;
11656
11657                        // Move all selections in this group up by the total number of duplicated rows
11658                        for selection in group_selections {
11659                            let new_start = Point::new(
11660                                selection.start.row.saturating_sub(row_count),
11661                                selection.start.column,
11662                            );
11663
11664                            let new_end = Point::new(
11665                                selection.end.row.saturating_sub(row_count),
11666                                selection.end.column,
11667                            );
11668
11669                            new_ranges.push(new_start..new_end);
11670                        }
11671                    }
11672
11673                    s.select_ranges(new_ranges);
11674                });
11675            }
11676
11677            this.request_autoscroll(Autoscroll::fit(), cx);
11678        });
11679    }
11680
11681    pub fn duplicate_line_up(
11682        &mut self,
11683        _: &DuplicateLineUp,
11684        window: &mut Window,
11685        cx: &mut Context<Self>,
11686    ) {
11687        self.duplicate(true, true, window, cx);
11688    }
11689
11690    pub fn duplicate_line_down(
11691        &mut self,
11692        _: &DuplicateLineDown,
11693        window: &mut Window,
11694        cx: &mut Context<Self>,
11695    ) {
11696        self.duplicate(false, true, window, cx);
11697    }
11698
11699    pub fn duplicate_selection(
11700        &mut self,
11701        _: &DuplicateSelection,
11702        window: &mut Window,
11703        cx: &mut Context<Self>,
11704    ) {
11705        self.duplicate(false, false, window, cx);
11706    }
11707
11708    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11709        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11710        if self.mode.is_single_line() {
11711            cx.propagate();
11712            return;
11713        }
11714
11715        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11716        let buffer = self.buffer.read(cx).snapshot(cx);
11717
11718        let mut edits = Vec::new();
11719        let mut unfold_ranges = Vec::new();
11720        let mut refold_creases = Vec::new();
11721
11722        let selections = self.selections.all::<Point>(&display_map);
11723        let mut selections = selections.iter().peekable();
11724        let mut contiguous_row_selections = Vec::new();
11725        let mut new_selections = Vec::new();
11726
11727        while let Some(selection) = selections.next() {
11728            // Find all the selections that span a contiguous row range
11729            let (start_row, end_row) = consume_contiguous_rows(
11730                &mut contiguous_row_selections,
11731                selection,
11732                &display_map,
11733                &mut selections,
11734            );
11735
11736            // Move the text spanned by the row range to be before the line preceding the row range
11737            if start_row.0 > 0 {
11738                let range_to_move = Point::new(
11739                    start_row.previous_row().0,
11740                    buffer.line_len(start_row.previous_row()),
11741                )
11742                    ..Point::new(
11743                        end_row.previous_row().0,
11744                        buffer.line_len(end_row.previous_row()),
11745                    );
11746                let insertion_point = display_map
11747                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11748                    .0;
11749
11750                // Don't move lines across excerpts
11751                if buffer
11752                    .excerpt_containing(insertion_point..range_to_move.end)
11753                    .is_some()
11754                {
11755                    let text = buffer
11756                        .text_for_range(range_to_move.clone())
11757                        .flat_map(|s| s.chars())
11758                        .skip(1)
11759                        .chain(['\n'])
11760                        .collect::<String>();
11761
11762                    edits.push((
11763                        buffer.anchor_after(range_to_move.start)
11764                            ..buffer.anchor_before(range_to_move.end),
11765                        String::new(),
11766                    ));
11767                    let insertion_anchor = buffer.anchor_after(insertion_point);
11768                    edits.push((insertion_anchor..insertion_anchor, text));
11769
11770                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11771
11772                    // Move selections up
11773                    new_selections.extend(contiguous_row_selections.drain(..).map(
11774                        |mut selection| {
11775                            selection.start.row -= row_delta;
11776                            selection.end.row -= row_delta;
11777                            selection
11778                        },
11779                    ));
11780
11781                    // Move folds up
11782                    unfold_ranges.push(range_to_move.clone());
11783                    for fold in display_map.folds_in_range(
11784                        buffer.anchor_before(range_to_move.start)
11785                            ..buffer.anchor_after(range_to_move.end),
11786                    ) {
11787                        let mut start = fold.range.start.to_point(&buffer);
11788                        let mut end = fold.range.end.to_point(&buffer);
11789                        start.row -= row_delta;
11790                        end.row -= row_delta;
11791                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11792                    }
11793                }
11794            }
11795
11796            // If we didn't move line(s), preserve the existing selections
11797            new_selections.append(&mut contiguous_row_selections);
11798        }
11799
11800        self.transact(window, cx, |this, window, cx| {
11801            this.unfold_ranges(&unfold_ranges, true, true, cx);
11802            this.buffer.update(cx, |buffer, cx| {
11803                for (range, text) in edits {
11804                    buffer.edit([(range, text)], None, cx);
11805                }
11806            });
11807            this.fold_creases(refold_creases, true, window, cx);
11808            this.change_selections(Default::default(), window, cx, |s| {
11809                s.select(new_selections);
11810            })
11811        });
11812    }
11813
11814    pub fn move_line_down(
11815        &mut self,
11816        _: &MoveLineDown,
11817        window: &mut Window,
11818        cx: &mut Context<Self>,
11819    ) {
11820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11821        if self.mode.is_single_line() {
11822            cx.propagate();
11823            return;
11824        }
11825
11826        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11827        let buffer = self.buffer.read(cx).snapshot(cx);
11828
11829        let mut edits = Vec::new();
11830        let mut unfold_ranges = Vec::new();
11831        let mut refold_creases = Vec::new();
11832
11833        let selections = self.selections.all::<Point>(&display_map);
11834        let mut selections = selections.iter().peekable();
11835        let mut contiguous_row_selections = Vec::new();
11836        let mut new_selections = Vec::new();
11837
11838        while let Some(selection) = selections.next() {
11839            // Find all the selections that span a contiguous row range
11840            let (start_row, end_row) = consume_contiguous_rows(
11841                &mut contiguous_row_selections,
11842                selection,
11843                &display_map,
11844                &mut selections,
11845            );
11846
11847            // Move the text spanned by the row range to be after the last line of the row range
11848            if end_row.0 <= buffer.max_point().row {
11849                let range_to_move =
11850                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11851                let insertion_point = display_map
11852                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11853                    .0;
11854
11855                // Don't move lines across excerpt boundaries
11856                if buffer
11857                    .excerpt_containing(range_to_move.start..insertion_point)
11858                    .is_some()
11859                {
11860                    let mut text = String::from("\n");
11861                    text.extend(buffer.text_for_range(range_to_move.clone()));
11862                    text.pop(); // Drop trailing newline
11863                    edits.push((
11864                        buffer.anchor_after(range_to_move.start)
11865                            ..buffer.anchor_before(range_to_move.end),
11866                        String::new(),
11867                    ));
11868                    let insertion_anchor = buffer.anchor_after(insertion_point);
11869                    edits.push((insertion_anchor..insertion_anchor, text));
11870
11871                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11872
11873                    // Move selections down
11874                    new_selections.extend(contiguous_row_selections.drain(..).map(
11875                        |mut selection| {
11876                            selection.start.row += row_delta;
11877                            selection.end.row += row_delta;
11878                            selection
11879                        },
11880                    ));
11881
11882                    // Move folds down
11883                    unfold_ranges.push(range_to_move.clone());
11884                    for fold in display_map.folds_in_range(
11885                        buffer.anchor_before(range_to_move.start)
11886                            ..buffer.anchor_after(range_to_move.end),
11887                    ) {
11888                        let mut start = fold.range.start.to_point(&buffer);
11889                        let mut end = fold.range.end.to_point(&buffer);
11890                        start.row += row_delta;
11891                        end.row += row_delta;
11892                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11893                    }
11894                }
11895            }
11896
11897            // If we didn't move line(s), preserve the existing selections
11898            new_selections.append(&mut contiguous_row_selections);
11899        }
11900
11901        self.transact(window, cx, |this, window, cx| {
11902            this.unfold_ranges(&unfold_ranges, true, true, cx);
11903            this.buffer.update(cx, |buffer, cx| {
11904                for (range, text) in edits {
11905                    buffer.edit([(range, text)], None, cx);
11906                }
11907            });
11908            this.fold_creases(refold_creases, true, window, cx);
11909            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11910        });
11911    }
11912
11913    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11914        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11915        let text_layout_details = &self.text_layout_details(window);
11916        self.transact(window, cx, |this, window, cx| {
11917            let edits = this.change_selections(Default::default(), window, cx, |s| {
11918                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11919                s.move_with(|display_map, selection| {
11920                    if !selection.is_empty() {
11921                        return;
11922                    }
11923
11924                    let mut head = selection.head();
11925                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11926                    if head.column() == display_map.line_len(head.row()) {
11927                        transpose_offset = display_map
11928                            .buffer_snapshot()
11929                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11930                    }
11931
11932                    if transpose_offset == 0 {
11933                        return;
11934                    }
11935
11936                    *head.column_mut() += 1;
11937                    head = display_map.clip_point(head, Bias::Right);
11938                    let goal = SelectionGoal::HorizontalPosition(
11939                        display_map
11940                            .x_for_display_point(head, text_layout_details)
11941                            .into(),
11942                    );
11943                    selection.collapse_to(head, goal);
11944
11945                    let transpose_start = display_map
11946                        .buffer_snapshot()
11947                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11948                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11949                        let transpose_end = display_map
11950                            .buffer_snapshot()
11951                            .clip_offset(transpose_offset + 1, Bias::Right);
11952                        if let Some(ch) = display_map
11953                            .buffer_snapshot()
11954                            .chars_at(transpose_start)
11955                            .next()
11956                        {
11957                            edits.push((transpose_start..transpose_offset, String::new()));
11958                            edits.push((transpose_end..transpose_end, ch.to_string()));
11959                        }
11960                    }
11961                });
11962                edits
11963            });
11964            this.buffer
11965                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11966            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
11967            this.change_selections(Default::default(), window, cx, |s| {
11968                s.select(selections);
11969            });
11970        });
11971    }
11972
11973    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11974        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11975        if self.mode.is_single_line() {
11976            cx.propagate();
11977            return;
11978        }
11979
11980        self.rewrap_impl(RewrapOptions::default(), cx)
11981    }
11982
11983    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11984        let buffer = self.buffer.read(cx).snapshot(cx);
11985        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11986
11987        #[derive(Clone, Debug, PartialEq)]
11988        enum CommentFormat {
11989            /// single line comment, with prefix for line
11990            Line(String),
11991            /// single line within a block comment, with prefix for line
11992            BlockLine(String),
11993            /// a single line of a block comment that includes the initial delimiter
11994            BlockCommentWithStart(BlockCommentConfig),
11995            /// a single line of a block comment that includes the ending delimiter
11996            BlockCommentWithEnd(BlockCommentConfig),
11997        }
11998
11999        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12000        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12001            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12002                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12003                .peekable();
12004
12005            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12006                row
12007            } else {
12008                return Vec::new();
12009            };
12010
12011            let language_settings = buffer.language_settings_at(selection.head(), cx);
12012            let language_scope = buffer.language_scope_at(selection.head());
12013
12014            let indent_and_prefix_for_row =
12015                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12016                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12017                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12018                        &language_scope
12019                    {
12020                        let indent_end = Point::new(row, indent.len);
12021                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12022                        let line_text_after_indent = buffer
12023                            .text_for_range(indent_end..line_end)
12024                            .collect::<String>();
12025
12026                        let is_within_comment_override = buffer
12027                            .language_scope_at(indent_end)
12028                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12029                        let comment_delimiters = if is_within_comment_override {
12030                            // we are within a comment syntax node, but we don't
12031                            // yet know what kind of comment: block, doc or line
12032                            match (
12033                                language_scope.documentation_comment(),
12034                                language_scope.block_comment(),
12035                            ) {
12036                                (Some(config), _) | (_, Some(config))
12037                                    if buffer.contains_str_at(indent_end, &config.start) =>
12038                                {
12039                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12040                                }
12041                                (Some(config), _) | (_, Some(config))
12042                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12043                                {
12044                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12045                                }
12046                                (Some(config), _) | (_, Some(config))
12047                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12048                                {
12049                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12050                                }
12051                                (_, _) => language_scope
12052                                    .line_comment_prefixes()
12053                                    .iter()
12054                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12055                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12056                            }
12057                        } else {
12058                            // we not in an overridden comment node, but we may
12059                            // be within a non-overridden line comment node
12060                            language_scope
12061                                .line_comment_prefixes()
12062                                .iter()
12063                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12064                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12065                        };
12066
12067                        let rewrap_prefix = language_scope
12068                            .rewrap_prefixes()
12069                            .iter()
12070                            .find_map(|prefix_regex| {
12071                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12072                                    if mat.start() == 0 {
12073                                        Some(mat.as_str().to_string())
12074                                    } else {
12075                                        None
12076                                    }
12077                                })
12078                            })
12079                            .flatten();
12080                        (comment_delimiters, rewrap_prefix)
12081                    } else {
12082                        (None, None)
12083                    };
12084                    (indent, comment_prefix, rewrap_prefix)
12085                };
12086
12087            let mut ranges = Vec::new();
12088            let from_empty_selection = selection.is_empty();
12089
12090            let mut current_range_start = first_row;
12091            let mut prev_row = first_row;
12092            let (
12093                mut current_range_indent,
12094                mut current_range_comment_delimiters,
12095                mut current_range_rewrap_prefix,
12096            ) = indent_and_prefix_for_row(first_row);
12097
12098            for row in non_blank_rows_iter.skip(1) {
12099                let has_paragraph_break = row > prev_row + 1;
12100
12101                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12102                    indent_and_prefix_for_row(row);
12103
12104                let has_indent_change = row_indent != current_range_indent;
12105                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12106
12107                let has_boundary_change = has_comment_change
12108                    || row_rewrap_prefix.is_some()
12109                    || (has_indent_change && current_range_comment_delimiters.is_some());
12110
12111                if has_paragraph_break || has_boundary_change {
12112                    ranges.push((
12113                        language_settings.clone(),
12114                        Point::new(current_range_start, 0)
12115                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12116                        current_range_indent,
12117                        current_range_comment_delimiters.clone(),
12118                        current_range_rewrap_prefix.clone(),
12119                        from_empty_selection,
12120                    ));
12121                    current_range_start = row;
12122                    current_range_indent = row_indent;
12123                    current_range_comment_delimiters = row_comment_delimiters;
12124                    current_range_rewrap_prefix = row_rewrap_prefix;
12125                }
12126                prev_row = row;
12127            }
12128
12129            ranges.push((
12130                language_settings.clone(),
12131                Point::new(current_range_start, 0)
12132                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12133                current_range_indent,
12134                current_range_comment_delimiters,
12135                current_range_rewrap_prefix,
12136                from_empty_selection,
12137            ));
12138
12139            ranges
12140        });
12141
12142        let mut edits = Vec::new();
12143        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12144
12145        for (
12146            language_settings,
12147            wrap_range,
12148            mut indent_size,
12149            comment_prefix,
12150            rewrap_prefix,
12151            from_empty_selection,
12152        ) in wrap_ranges
12153        {
12154            let mut start_row = wrap_range.start.row;
12155            let mut end_row = wrap_range.end.row;
12156
12157            // Skip selections that overlap with a range that has already been rewrapped.
12158            let selection_range = start_row..end_row;
12159            if rewrapped_row_ranges
12160                .iter()
12161                .any(|range| range.overlaps(&selection_range))
12162            {
12163                continue;
12164            }
12165
12166            let tab_size = language_settings.tab_size;
12167
12168            let (line_prefix, inside_comment) = match &comment_prefix {
12169                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12170                    (Some(prefix.as_str()), true)
12171                }
12172                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12173                    (Some(prefix.as_ref()), true)
12174                }
12175                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12176                    start: _,
12177                    end: _,
12178                    prefix,
12179                    tab_size,
12180                })) => {
12181                    indent_size.len += tab_size;
12182                    (Some(prefix.as_ref()), true)
12183                }
12184                None => (None, false),
12185            };
12186            let indent_prefix = indent_size.chars().collect::<String>();
12187            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12188
12189            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12190                RewrapBehavior::InComments => inside_comment,
12191                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12192                RewrapBehavior::Anywhere => true,
12193            };
12194
12195            let should_rewrap = options.override_language_settings
12196                || allow_rewrap_based_on_language
12197                || self.hard_wrap.is_some();
12198            if !should_rewrap {
12199                continue;
12200            }
12201
12202            if from_empty_selection {
12203                'expand_upwards: while start_row > 0 {
12204                    let prev_row = start_row - 1;
12205                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12206                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12207                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12208                    {
12209                        start_row = prev_row;
12210                    } else {
12211                        break 'expand_upwards;
12212                    }
12213                }
12214
12215                'expand_downwards: while end_row < buffer.max_point().row {
12216                    let next_row = end_row + 1;
12217                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12218                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12219                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12220                    {
12221                        end_row = next_row;
12222                    } else {
12223                        break 'expand_downwards;
12224                    }
12225                }
12226            }
12227
12228            let start = Point::new(start_row, 0);
12229            let start_offset = ToOffset::to_offset(&start, &buffer);
12230            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12231            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12232            let mut first_line_delimiter = None;
12233            let mut last_line_delimiter = None;
12234            let Some(lines_without_prefixes) = selection_text
12235                .lines()
12236                .enumerate()
12237                .map(|(ix, line)| {
12238                    let line_trimmed = line.trim_start();
12239                    if rewrap_prefix.is_some() && ix > 0 {
12240                        Ok(line_trimmed)
12241                    } else if let Some(
12242                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12243                            start,
12244                            prefix,
12245                            end,
12246                            tab_size,
12247                        })
12248                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12249                            start,
12250                            prefix,
12251                            end,
12252                            tab_size,
12253                        }),
12254                    ) = &comment_prefix
12255                    {
12256                        let line_trimmed = line_trimmed
12257                            .strip_prefix(start.as_ref())
12258                            .map(|s| {
12259                                let mut indent_size = indent_size;
12260                                indent_size.len -= tab_size;
12261                                let indent_prefix: String = indent_size.chars().collect();
12262                                first_line_delimiter = Some((indent_prefix, start));
12263                                s.trim_start()
12264                            })
12265                            .unwrap_or(line_trimmed);
12266                        let line_trimmed = line_trimmed
12267                            .strip_suffix(end.as_ref())
12268                            .map(|s| {
12269                                last_line_delimiter = Some(end);
12270                                s.trim_end()
12271                            })
12272                            .unwrap_or(line_trimmed);
12273                        let line_trimmed = line_trimmed
12274                            .strip_prefix(prefix.as_ref())
12275                            .unwrap_or(line_trimmed);
12276                        Ok(line_trimmed)
12277                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12278                        line_trimmed.strip_prefix(prefix).with_context(|| {
12279                            format!("line did not start with prefix {prefix:?}: {line:?}")
12280                        })
12281                    } else {
12282                        line_trimmed
12283                            .strip_prefix(&line_prefix.trim_start())
12284                            .with_context(|| {
12285                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12286                            })
12287                    }
12288                })
12289                .collect::<Result<Vec<_>, _>>()
12290                .log_err()
12291            else {
12292                continue;
12293            };
12294
12295            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12296                buffer
12297                    .language_settings_at(Point::new(start_row, 0), cx)
12298                    .preferred_line_length as usize
12299            });
12300
12301            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12302                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12303            } else {
12304                line_prefix.clone()
12305            };
12306
12307            let wrapped_text = {
12308                let mut wrapped_text = wrap_with_prefix(
12309                    line_prefix,
12310                    subsequent_lines_prefix,
12311                    lines_without_prefixes.join("\n"),
12312                    wrap_column,
12313                    tab_size,
12314                    options.preserve_existing_whitespace,
12315                );
12316
12317                if let Some((indent, delimiter)) = first_line_delimiter {
12318                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12319                }
12320                if let Some(last_line) = last_line_delimiter {
12321                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12322                }
12323
12324                wrapped_text
12325            };
12326
12327            // TODO: should always use char-based diff while still supporting cursor behavior that
12328            // matches vim.
12329            let mut diff_options = DiffOptions::default();
12330            if options.override_language_settings {
12331                diff_options.max_word_diff_len = 0;
12332                diff_options.max_word_diff_line_count = 0;
12333            } else {
12334                diff_options.max_word_diff_len = usize::MAX;
12335                diff_options.max_word_diff_line_count = usize::MAX;
12336            }
12337
12338            for (old_range, new_text) in
12339                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12340            {
12341                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12342                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12343                edits.push((edit_start..edit_end, new_text));
12344            }
12345
12346            rewrapped_row_ranges.push(start_row..=end_row);
12347        }
12348
12349        self.buffer
12350            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12351    }
12352
12353    pub fn cut_common(
12354        &mut self,
12355        cut_no_selection_line: bool,
12356        window: &mut Window,
12357        cx: &mut Context<Self>,
12358    ) -> ClipboardItem {
12359        let mut text = String::new();
12360        let buffer = self.buffer.read(cx).snapshot(cx);
12361        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12362        let mut clipboard_selections = Vec::with_capacity(selections.len());
12363        {
12364            let max_point = buffer.max_point();
12365            let mut is_first = true;
12366            for selection in &mut selections {
12367                let is_entire_line =
12368                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12369                if is_entire_line {
12370                    selection.start = Point::new(selection.start.row, 0);
12371                    if !selection.is_empty() && selection.end.column == 0 {
12372                        selection.end = cmp::min(max_point, selection.end);
12373                    } else {
12374                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12375                    }
12376                    selection.goal = SelectionGoal::None;
12377                }
12378                if is_first {
12379                    is_first = false;
12380                } else {
12381                    text += "\n";
12382                }
12383                let mut len = 0;
12384                for chunk in buffer.text_for_range(selection.start..selection.end) {
12385                    text.push_str(chunk);
12386                    len += chunk.len();
12387                }
12388                clipboard_selections.push(ClipboardSelection {
12389                    len,
12390                    is_entire_line,
12391                    first_line_indent: buffer
12392                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12393                        .len,
12394                });
12395            }
12396        }
12397
12398        self.transact(window, cx, |this, window, cx| {
12399            this.change_selections(Default::default(), window, cx, |s| {
12400                s.select(selections);
12401            });
12402            this.insert("", window, cx);
12403        });
12404        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12405    }
12406
12407    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12408        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12409        let item = self.cut_common(true, window, cx);
12410        cx.write_to_clipboard(item);
12411    }
12412
12413    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12414        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12415        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12416            s.move_with(|snapshot, sel| {
12417                if sel.is_empty() {
12418                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12419                }
12420                if sel.is_empty() {
12421                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12422                }
12423            });
12424        });
12425        let item = self.cut_common(false, window, cx);
12426        cx.set_global(KillRing(item))
12427    }
12428
12429    pub fn kill_ring_yank(
12430        &mut self,
12431        _: &KillRingYank,
12432        window: &mut Window,
12433        cx: &mut Context<Self>,
12434    ) {
12435        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12436        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12437            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12438                (kill_ring.text().to_string(), kill_ring.metadata_json())
12439            } else {
12440                return;
12441            }
12442        } else {
12443            return;
12444        };
12445        self.do_paste(&text, metadata, false, window, cx);
12446    }
12447
12448    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12449        self.do_copy(true, cx);
12450    }
12451
12452    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12453        self.do_copy(false, cx);
12454    }
12455
12456    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12457        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12458        let buffer = self.buffer.read(cx).read(cx);
12459        let mut text = String::new();
12460
12461        let mut clipboard_selections = Vec::with_capacity(selections.len());
12462        {
12463            let max_point = buffer.max_point();
12464            let mut is_first = true;
12465            for selection in &selections {
12466                let mut start = selection.start;
12467                let mut end = selection.end;
12468                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12469                let mut add_trailing_newline = false;
12470                if is_entire_line {
12471                    start = Point::new(start.row, 0);
12472                    let next_line_start = Point::new(end.row + 1, 0);
12473                    if next_line_start <= max_point {
12474                        end = next_line_start;
12475                    } else {
12476                        // We're on the last line without a trailing newline.
12477                        // Copy to the end of the line and add a newline afterwards.
12478                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12479                        add_trailing_newline = true;
12480                    }
12481                }
12482
12483                let mut trimmed_selections = Vec::new();
12484                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12485                    let row = MultiBufferRow(start.row);
12486                    let first_indent = buffer.indent_size_for_line(row);
12487                    if first_indent.len == 0 || start.column > first_indent.len {
12488                        trimmed_selections.push(start..end);
12489                    } else {
12490                        trimmed_selections.push(
12491                            Point::new(row.0, first_indent.len)
12492                                ..Point::new(row.0, buffer.line_len(row)),
12493                        );
12494                        for row in start.row + 1..=end.row {
12495                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12496                            if row == end.row {
12497                                line_len = end.column;
12498                            }
12499                            if line_len == 0 {
12500                                trimmed_selections
12501                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12502                                continue;
12503                            }
12504                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12505                            if row_indent_size.len >= first_indent.len {
12506                                trimmed_selections.push(
12507                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12508                                );
12509                            } else {
12510                                trimmed_selections.clear();
12511                                trimmed_selections.push(start..end);
12512                                break;
12513                            }
12514                        }
12515                    }
12516                } else {
12517                    trimmed_selections.push(start..end);
12518                }
12519
12520                for trimmed_range in trimmed_selections {
12521                    if is_first {
12522                        is_first = false;
12523                    } else {
12524                        text += "\n";
12525                    }
12526                    let mut len = 0;
12527                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12528                        text.push_str(chunk);
12529                        len += chunk.len();
12530                    }
12531                    if add_trailing_newline {
12532                        text.push('\n');
12533                        len += 1;
12534                    }
12535                    clipboard_selections.push(ClipboardSelection {
12536                        len,
12537                        is_entire_line,
12538                        first_line_indent: buffer
12539                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12540                            .len,
12541                    });
12542                }
12543            }
12544        }
12545
12546        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12547            text,
12548            clipboard_selections,
12549        ));
12550    }
12551
12552    pub fn do_paste(
12553        &mut self,
12554        text: &String,
12555        clipboard_selections: Option<Vec<ClipboardSelection>>,
12556        handle_entire_lines: bool,
12557        window: &mut Window,
12558        cx: &mut Context<Self>,
12559    ) {
12560        if self.read_only(cx) {
12561            return;
12562        }
12563
12564        let clipboard_text = Cow::Borrowed(text.as_str());
12565
12566        self.transact(window, cx, |this, window, cx| {
12567            let had_active_edit_prediction = this.has_active_edit_prediction();
12568            let display_map = this.display_snapshot(cx);
12569            let old_selections = this.selections.all::<usize>(&display_map);
12570            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12571
12572            if let Some(mut clipboard_selections) = clipboard_selections {
12573                let all_selections_were_entire_line =
12574                    clipboard_selections.iter().all(|s| s.is_entire_line);
12575                let first_selection_indent_column =
12576                    clipboard_selections.first().map(|s| s.first_line_indent);
12577                if clipboard_selections.len() != old_selections.len() {
12578                    clipboard_selections.drain(..);
12579                }
12580                let mut auto_indent_on_paste = true;
12581
12582                this.buffer.update(cx, |buffer, cx| {
12583                    let snapshot = buffer.read(cx);
12584                    auto_indent_on_paste = snapshot
12585                        .language_settings_at(cursor_offset, cx)
12586                        .auto_indent_on_paste;
12587
12588                    let mut start_offset = 0;
12589                    let mut edits = Vec::new();
12590                    let mut original_indent_columns = Vec::new();
12591                    for (ix, selection) in old_selections.iter().enumerate() {
12592                        let to_insert;
12593                        let entire_line;
12594                        let original_indent_column;
12595                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12596                            let end_offset = start_offset + clipboard_selection.len;
12597                            to_insert = &clipboard_text[start_offset..end_offset];
12598                            entire_line = clipboard_selection.is_entire_line;
12599                            start_offset = end_offset + 1;
12600                            original_indent_column = Some(clipboard_selection.first_line_indent);
12601                        } else {
12602                            to_insert = &*clipboard_text;
12603                            entire_line = all_selections_were_entire_line;
12604                            original_indent_column = first_selection_indent_column
12605                        }
12606
12607                        let (range, to_insert) =
12608                            if selection.is_empty() && handle_entire_lines && entire_line {
12609                                // If the corresponding selection was empty when this slice of the
12610                                // clipboard text was written, then the entire line containing the
12611                                // selection was copied. If this selection is also currently empty,
12612                                // then paste the line before the current line of the buffer.
12613                                let column = selection.start.to_point(&snapshot).column as usize;
12614                                let line_start = selection.start - column;
12615                                (line_start..line_start, Cow::Borrowed(to_insert))
12616                            } else {
12617                                let language = snapshot.language_at(selection.head());
12618                                let range = selection.range();
12619                                if let Some(language) = language
12620                                    && language.name() == "Markdown".into()
12621                                {
12622                                    edit_for_markdown_paste(
12623                                        &snapshot,
12624                                        range,
12625                                        to_insert,
12626                                        url::Url::parse(to_insert).ok(),
12627                                    )
12628                                } else {
12629                                    (range, Cow::Borrowed(to_insert))
12630                                }
12631                            };
12632
12633                        edits.push((range, to_insert));
12634                        original_indent_columns.push(original_indent_column);
12635                    }
12636                    drop(snapshot);
12637
12638                    buffer.edit(
12639                        edits,
12640                        if auto_indent_on_paste {
12641                            Some(AutoindentMode::Block {
12642                                original_indent_columns,
12643                            })
12644                        } else {
12645                            None
12646                        },
12647                        cx,
12648                    );
12649                });
12650
12651                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12652                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12653            } else {
12654                let url = url::Url::parse(&clipboard_text).ok();
12655
12656                let auto_indent_mode = if !clipboard_text.is_empty() {
12657                    Some(AutoindentMode::Block {
12658                        original_indent_columns: Vec::new(),
12659                    })
12660                } else {
12661                    None
12662                };
12663
12664                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12665                    let snapshot = buffer.snapshot(cx);
12666
12667                    let anchors = old_selections
12668                        .iter()
12669                        .map(|s| {
12670                            let anchor = snapshot.anchor_after(s.head());
12671                            s.map(|_| anchor)
12672                        })
12673                        .collect::<Vec<_>>();
12674
12675                    let mut edits = Vec::new();
12676
12677                    for selection in old_selections.iter() {
12678                        let language = snapshot.language_at(selection.head());
12679                        let range = selection.range();
12680
12681                        let (edit_range, edit_text) = if let Some(language) = language
12682                            && language.name() == "Markdown".into()
12683                        {
12684                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12685                        } else {
12686                            (range, clipboard_text.clone())
12687                        };
12688
12689                        edits.push((edit_range, edit_text));
12690                    }
12691
12692                    drop(snapshot);
12693                    buffer.edit(edits, auto_indent_mode, cx);
12694
12695                    anchors
12696                });
12697
12698                this.change_selections(Default::default(), window, cx, |s| {
12699                    s.select_anchors(selection_anchors);
12700                });
12701            }
12702
12703            let trigger_in_words =
12704                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12705
12706            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12707        });
12708    }
12709
12710    pub fn diff_clipboard_with_selection(
12711        &mut self,
12712        _: &DiffClipboardWithSelection,
12713        window: &mut Window,
12714        cx: &mut Context<Self>,
12715    ) {
12716        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12717
12718        if selections.is_empty() {
12719            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12720            return;
12721        };
12722
12723        let clipboard_text = match cx.read_from_clipboard() {
12724            Some(item) => match item.entries().first() {
12725                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12726                _ => None,
12727            },
12728            None => None,
12729        };
12730
12731        let Some(clipboard_text) = clipboard_text else {
12732            log::warn!("Clipboard doesn't contain text.");
12733            return;
12734        };
12735
12736        window.dispatch_action(
12737            Box::new(DiffClipboardWithSelectionData {
12738                clipboard_text,
12739                editor: cx.entity(),
12740            }),
12741            cx,
12742        );
12743    }
12744
12745    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12746        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12747        if let Some(item) = cx.read_from_clipboard() {
12748            let entries = item.entries();
12749
12750            match entries.first() {
12751                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12752                // of all the pasted entries.
12753                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12754                    .do_paste(
12755                        clipboard_string.text(),
12756                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12757                        true,
12758                        window,
12759                        cx,
12760                    ),
12761                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12762            }
12763        }
12764    }
12765
12766    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12767        if self.read_only(cx) {
12768            return;
12769        }
12770
12771        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12772
12773        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12774            if let Some((selections, _)) =
12775                self.selection_history.transaction(transaction_id).cloned()
12776            {
12777                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12778                    s.select_anchors(selections.to_vec());
12779                });
12780            } else {
12781                log::error!(
12782                    "No entry in selection_history found for undo. \
12783                     This may correspond to a bug where undo does not update the selection. \
12784                     If this is occurring, please add details to \
12785                     https://github.com/zed-industries/zed/issues/22692"
12786                );
12787            }
12788            self.request_autoscroll(Autoscroll::fit(), cx);
12789            self.unmark_text(window, cx);
12790            self.refresh_edit_prediction(true, false, window, cx);
12791            cx.emit(EditorEvent::Edited { transaction_id });
12792            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12793        }
12794    }
12795
12796    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12797        if self.read_only(cx) {
12798            return;
12799        }
12800
12801        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12802
12803        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12804            if let Some((_, Some(selections))) =
12805                self.selection_history.transaction(transaction_id).cloned()
12806            {
12807                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12808                    s.select_anchors(selections.to_vec());
12809                });
12810            } else {
12811                log::error!(
12812                    "No entry in selection_history found for redo. \
12813                     This may correspond to a bug where undo does not update the selection. \
12814                     If this is occurring, please add details to \
12815                     https://github.com/zed-industries/zed/issues/22692"
12816                );
12817            }
12818            self.request_autoscroll(Autoscroll::fit(), cx);
12819            self.unmark_text(window, cx);
12820            self.refresh_edit_prediction(true, false, window, cx);
12821            cx.emit(EditorEvent::Edited { transaction_id });
12822        }
12823    }
12824
12825    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12826        self.buffer
12827            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12828    }
12829
12830    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12831        self.buffer
12832            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12833    }
12834
12835    pub fn move_left(&mut self, _: &MoveLeft, 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_with(|map, selection| {
12839                let cursor = if selection.is_empty() {
12840                    movement::left(map, selection.start)
12841                } else {
12842                    selection.start
12843                };
12844                selection.collapse_to(cursor, SelectionGoal::None);
12845            });
12846        })
12847    }
12848
12849    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12850        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12851        self.change_selections(Default::default(), window, cx, |s| {
12852            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12853        })
12854    }
12855
12856    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12858        self.change_selections(Default::default(), window, cx, |s| {
12859            s.move_with(|map, selection| {
12860                let cursor = if selection.is_empty() {
12861                    movement::right(map, selection.end)
12862                } else {
12863                    selection.end
12864                };
12865                selection.collapse_to(cursor, SelectionGoal::None)
12866            });
12867        })
12868    }
12869
12870    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12871        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12872        self.change_selections(Default::default(), window, cx, |s| {
12873            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12874        });
12875    }
12876
12877    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12878        if self.take_rename(true, window, cx).is_some() {
12879            return;
12880        }
12881
12882        if self.mode.is_single_line() {
12883            cx.propagate();
12884            return;
12885        }
12886
12887        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12888
12889        let text_layout_details = &self.text_layout_details(window);
12890        let selection_count = self.selections.count();
12891        let first_selection = self.selections.first_anchor();
12892
12893        self.change_selections(Default::default(), window, cx, |s| {
12894            s.move_with(|map, selection| {
12895                if !selection.is_empty() {
12896                    selection.goal = SelectionGoal::None;
12897                }
12898                let (cursor, goal) = movement::up(
12899                    map,
12900                    selection.start,
12901                    selection.goal,
12902                    false,
12903                    text_layout_details,
12904                );
12905                selection.collapse_to(cursor, goal);
12906            });
12907        });
12908
12909        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12910        {
12911            cx.propagate();
12912        }
12913    }
12914
12915    pub fn move_up_by_lines(
12916        &mut self,
12917        action: &MoveUpByLines,
12918        window: &mut Window,
12919        cx: &mut Context<Self>,
12920    ) {
12921        if self.take_rename(true, window, cx).is_some() {
12922            return;
12923        }
12924
12925        if self.mode.is_single_line() {
12926            cx.propagate();
12927            return;
12928        }
12929
12930        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12931
12932        let text_layout_details = &self.text_layout_details(window);
12933
12934        self.change_selections(Default::default(), window, cx, |s| {
12935            s.move_with(|map, selection| {
12936                if !selection.is_empty() {
12937                    selection.goal = SelectionGoal::None;
12938                }
12939                let (cursor, goal) = movement::up_by_rows(
12940                    map,
12941                    selection.start,
12942                    action.lines,
12943                    selection.goal,
12944                    false,
12945                    text_layout_details,
12946                );
12947                selection.collapse_to(cursor, goal);
12948            });
12949        })
12950    }
12951
12952    pub fn move_down_by_lines(
12953        &mut self,
12954        action: &MoveDownByLines,
12955        window: &mut Window,
12956        cx: &mut Context<Self>,
12957    ) {
12958        if self.take_rename(true, window, cx).is_some() {
12959            return;
12960        }
12961
12962        if self.mode.is_single_line() {
12963            cx.propagate();
12964            return;
12965        }
12966
12967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12968
12969        let text_layout_details = &self.text_layout_details(window);
12970
12971        self.change_selections(Default::default(), window, cx, |s| {
12972            s.move_with(|map, selection| {
12973                if !selection.is_empty() {
12974                    selection.goal = SelectionGoal::None;
12975                }
12976                let (cursor, goal) = movement::down_by_rows(
12977                    map,
12978                    selection.start,
12979                    action.lines,
12980                    selection.goal,
12981                    false,
12982                    text_layout_details,
12983                );
12984                selection.collapse_to(cursor, goal);
12985            });
12986        })
12987    }
12988
12989    pub fn select_down_by_lines(
12990        &mut self,
12991        action: &SelectDownByLines,
12992        window: &mut Window,
12993        cx: &mut Context<Self>,
12994    ) {
12995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12996        let text_layout_details = &self.text_layout_details(window);
12997        self.change_selections(Default::default(), window, cx, |s| {
12998            s.move_heads_with(|map, head, goal| {
12999                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13000            })
13001        })
13002    }
13003
13004    pub fn select_up_by_lines(
13005        &mut self,
13006        action: &SelectUpByLines,
13007        window: &mut Window,
13008        cx: &mut Context<Self>,
13009    ) {
13010        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13011        let text_layout_details = &self.text_layout_details(window);
13012        self.change_selections(Default::default(), window, cx, |s| {
13013            s.move_heads_with(|map, head, goal| {
13014                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13015            })
13016        })
13017    }
13018
13019    pub fn select_page_up(
13020        &mut self,
13021        _: &SelectPageUp,
13022        window: &mut Window,
13023        cx: &mut Context<Self>,
13024    ) {
13025        let Some(row_count) = self.visible_row_count() else {
13026            return;
13027        };
13028
13029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13030
13031        let text_layout_details = &self.text_layout_details(window);
13032
13033        self.change_selections(Default::default(), window, cx, |s| {
13034            s.move_heads_with(|map, head, goal| {
13035                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13036            })
13037        })
13038    }
13039
13040    pub fn move_page_up(
13041        &mut self,
13042        action: &MovePageUp,
13043        window: &mut Window,
13044        cx: &mut Context<Self>,
13045    ) {
13046        if self.take_rename(true, window, cx).is_some() {
13047            return;
13048        }
13049
13050        if self
13051            .context_menu
13052            .borrow_mut()
13053            .as_mut()
13054            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13055            .unwrap_or(false)
13056        {
13057            return;
13058        }
13059
13060        if matches!(self.mode, EditorMode::SingleLine) {
13061            cx.propagate();
13062            return;
13063        }
13064
13065        let Some(row_count) = self.visible_row_count() else {
13066            return;
13067        };
13068
13069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13070
13071        let effects = if action.center_cursor {
13072            SelectionEffects::scroll(Autoscroll::center())
13073        } else {
13074            SelectionEffects::default()
13075        };
13076
13077        let text_layout_details = &self.text_layout_details(window);
13078
13079        self.change_selections(effects, window, cx, |s| {
13080            s.move_with(|map, selection| {
13081                if !selection.is_empty() {
13082                    selection.goal = SelectionGoal::None;
13083                }
13084                let (cursor, goal) = movement::up_by_rows(
13085                    map,
13086                    selection.end,
13087                    row_count,
13088                    selection.goal,
13089                    false,
13090                    text_layout_details,
13091                );
13092                selection.collapse_to(cursor, goal);
13093            });
13094        });
13095    }
13096
13097    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13099        let text_layout_details = &self.text_layout_details(window);
13100        self.change_selections(Default::default(), window, cx, |s| {
13101            s.move_heads_with(|map, head, goal| {
13102                movement::up(map, head, goal, false, text_layout_details)
13103            })
13104        })
13105    }
13106
13107    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13108        self.take_rename(true, window, cx);
13109
13110        if self.mode.is_single_line() {
13111            cx.propagate();
13112            return;
13113        }
13114
13115        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13116
13117        let text_layout_details = &self.text_layout_details(window);
13118        let selection_count = self.selections.count();
13119        let first_selection = self.selections.first_anchor();
13120
13121        self.change_selections(Default::default(), window, cx, |s| {
13122            s.move_with(|map, selection| {
13123                if !selection.is_empty() {
13124                    selection.goal = SelectionGoal::None;
13125                }
13126                let (cursor, goal) = movement::down(
13127                    map,
13128                    selection.end,
13129                    selection.goal,
13130                    false,
13131                    text_layout_details,
13132                );
13133                selection.collapse_to(cursor, goal);
13134            });
13135        });
13136
13137        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13138        {
13139            cx.propagate();
13140        }
13141    }
13142
13143    pub fn select_page_down(
13144        &mut self,
13145        _: &SelectPageDown,
13146        window: &mut Window,
13147        cx: &mut Context<Self>,
13148    ) {
13149        let Some(row_count) = self.visible_row_count() else {
13150            return;
13151        };
13152
13153        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13154
13155        let text_layout_details = &self.text_layout_details(window);
13156
13157        self.change_selections(Default::default(), window, cx, |s| {
13158            s.move_heads_with(|map, head, goal| {
13159                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13160            })
13161        })
13162    }
13163
13164    pub fn move_page_down(
13165        &mut self,
13166        action: &MovePageDown,
13167        window: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        if self.take_rename(true, window, cx).is_some() {
13171            return;
13172        }
13173
13174        if self
13175            .context_menu
13176            .borrow_mut()
13177            .as_mut()
13178            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13179            .unwrap_or(false)
13180        {
13181            return;
13182        }
13183
13184        if matches!(self.mode, EditorMode::SingleLine) {
13185            cx.propagate();
13186            return;
13187        }
13188
13189        let Some(row_count) = self.visible_row_count() else {
13190            return;
13191        };
13192
13193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13194
13195        let effects = if action.center_cursor {
13196            SelectionEffects::scroll(Autoscroll::center())
13197        } else {
13198            SelectionEffects::default()
13199        };
13200
13201        let text_layout_details = &self.text_layout_details(window);
13202        self.change_selections(effects, window, cx, |s| {
13203            s.move_with(|map, selection| {
13204                if !selection.is_empty() {
13205                    selection.goal = SelectionGoal::None;
13206                }
13207                let (cursor, goal) = movement::down_by_rows(
13208                    map,
13209                    selection.end,
13210                    row_count,
13211                    selection.goal,
13212                    false,
13213                    text_layout_details,
13214                );
13215                selection.collapse_to(cursor, goal);
13216            });
13217        });
13218    }
13219
13220    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13221        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13222        let text_layout_details = &self.text_layout_details(window);
13223        self.change_selections(Default::default(), window, cx, |s| {
13224            s.move_heads_with(|map, head, goal| {
13225                movement::down(map, head, goal, false, text_layout_details)
13226            })
13227        });
13228    }
13229
13230    pub fn context_menu_first(
13231        &mut self,
13232        _: &ContextMenuFirst,
13233        window: &mut Window,
13234        cx: &mut Context<Self>,
13235    ) {
13236        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13237            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13238        }
13239    }
13240
13241    pub fn context_menu_prev(
13242        &mut self,
13243        _: &ContextMenuPrevious,
13244        window: &mut Window,
13245        cx: &mut Context<Self>,
13246    ) {
13247        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13248            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13249        }
13250    }
13251
13252    pub fn context_menu_next(
13253        &mut self,
13254        _: &ContextMenuNext,
13255        window: &mut Window,
13256        cx: &mut Context<Self>,
13257    ) {
13258        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13259            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13260        }
13261    }
13262
13263    pub fn context_menu_last(
13264        &mut self,
13265        _: &ContextMenuLast,
13266        window: &mut Window,
13267        cx: &mut Context<Self>,
13268    ) {
13269        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13270            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13271        }
13272    }
13273
13274    pub fn signature_help_prev(
13275        &mut self,
13276        _: &SignatureHelpPrevious,
13277        _: &mut Window,
13278        cx: &mut Context<Self>,
13279    ) {
13280        if let Some(popover) = self.signature_help_state.popover_mut() {
13281            if popover.current_signature == 0 {
13282                popover.current_signature = popover.signatures.len() - 1;
13283            } else {
13284                popover.current_signature -= 1;
13285            }
13286            cx.notify();
13287        }
13288    }
13289
13290    pub fn signature_help_next(
13291        &mut self,
13292        _: &SignatureHelpNext,
13293        _: &mut Window,
13294        cx: &mut Context<Self>,
13295    ) {
13296        if let Some(popover) = self.signature_help_state.popover_mut() {
13297            if popover.current_signature + 1 == popover.signatures.len() {
13298                popover.current_signature = 0;
13299            } else {
13300                popover.current_signature += 1;
13301            }
13302            cx.notify();
13303        }
13304    }
13305
13306    pub fn move_to_previous_word_start(
13307        &mut self,
13308        _: &MoveToPreviousWordStart,
13309        window: &mut Window,
13310        cx: &mut Context<Self>,
13311    ) {
13312        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13313        self.change_selections(Default::default(), window, cx, |s| {
13314            s.move_cursors_with(|map, head, _| {
13315                (
13316                    movement::previous_word_start(map, head),
13317                    SelectionGoal::None,
13318                )
13319            });
13320        })
13321    }
13322
13323    pub fn move_to_previous_subword_start(
13324        &mut self,
13325        _: &MoveToPreviousSubwordStart,
13326        window: &mut Window,
13327        cx: &mut Context<Self>,
13328    ) {
13329        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13330        self.change_selections(Default::default(), window, cx, |s| {
13331            s.move_cursors_with(|map, head, _| {
13332                (
13333                    movement::previous_subword_start(map, head),
13334                    SelectionGoal::None,
13335                )
13336            });
13337        })
13338    }
13339
13340    pub fn select_to_previous_word_start(
13341        &mut self,
13342        _: &SelectToPreviousWordStart,
13343        window: &mut Window,
13344        cx: &mut Context<Self>,
13345    ) {
13346        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13347        self.change_selections(Default::default(), window, cx, |s| {
13348            s.move_heads_with(|map, head, _| {
13349                (
13350                    movement::previous_word_start(map, head),
13351                    SelectionGoal::None,
13352                )
13353            });
13354        })
13355    }
13356
13357    pub fn select_to_previous_subword_start(
13358        &mut self,
13359        _: &SelectToPreviousSubwordStart,
13360        window: &mut Window,
13361        cx: &mut Context<Self>,
13362    ) {
13363        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13364        self.change_selections(Default::default(), window, cx, |s| {
13365            s.move_heads_with(|map, head, _| {
13366                (
13367                    movement::previous_subword_start(map, head),
13368                    SelectionGoal::None,
13369                )
13370            });
13371        })
13372    }
13373
13374    pub fn delete_to_previous_word_start(
13375        &mut self,
13376        action: &DeleteToPreviousWordStart,
13377        window: &mut Window,
13378        cx: &mut Context<Self>,
13379    ) {
13380        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13381        self.transact(window, cx, |this, window, cx| {
13382            this.select_autoclose_pair(window, cx);
13383            this.change_selections(Default::default(), window, cx, |s| {
13384                s.move_with(|map, selection| {
13385                    if selection.is_empty() {
13386                        let mut cursor = if action.ignore_newlines {
13387                            movement::previous_word_start(map, selection.head())
13388                        } else {
13389                            movement::previous_word_start_or_newline(map, selection.head())
13390                        };
13391                        cursor = movement::adjust_greedy_deletion(
13392                            map,
13393                            selection.head(),
13394                            cursor,
13395                            action.ignore_brackets,
13396                        );
13397                        selection.set_head(cursor, SelectionGoal::None);
13398                    }
13399                });
13400            });
13401            this.insert("", window, cx);
13402        });
13403    }
13404
13405    pub fn delete_to_previous_subword_start(
13406        &mut self,
13407        _: &DeleteToPreviousSubwordStart,
13408        window: &mut Window,
13409        cx: &mut Context<Self>,
13410    ) {
13411        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13412        self.transact(window, cx, |this, window, cx| {
13413            this.select_autoclose_pair(window, cx);
13414            this.change_selections(Default::default(), window, cx, |s| {
13415                s.move_with(|map, selection| {
13416                    if selection.is_empty() {
13417                        let mut cursor = movement::previous_subword_start(map, selection.head());
13418                        cursor =
13419                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13420                        selection.set_head(cursor, SelectionGoal::None);
13421                    }
13422                });
13423            });
13424            this.insert("", window, cx);
13425        });
13426    }
13427
13428    pub fn move_to_next_word_end(
13429        &mut self,
13430        _: &MoveToNextWordEnd,
13431        window: &mut Window,
13432        cx: &mut Context<Self>,
13433    ) {
13434        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13435        self.change_selections(Default::default(), window, cx, |s| {
13436            s.move_cursors_with(|map, head, _| {
13437                (movement::next_word_end(map, head), SelectionGoal::None)
13438            });
13439        })
13440    }
13441
13442    pub fn move_to_next_subword_end(
13443        &mut self,
13444        _: &MoveToNextSubwordEnd,
13445        window: &mut Window,
13446        cx: &mut Context<Self>,
13447    ) {
13448        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13449        self.change_selections(Default::default(), window, cx, |s| {
13450            s.move_cursors_with(|map, head, _| {
13451                (movement::next_subword_end(map, head), SelectionGoal::None)
13452            });
13453        })
13454    }
13455
13456    pub fn select_to_next_word_end(
13457        &mut self,
13458        _: &SelectToNextWordEnd,
13459        window: &mut Window,
13460        cx: &mut Context<Self>,
13461    ) {
13462        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13463        self.change_selections(Default::default(), window, cx, |s| {
13464            s.move_heads_with(|map, head, _| {
13465                (movement::next_word_end(map, head), SelectionGoal::None)
13466            });
13467        })
13468    }
13469
13470    pub fn select_to_next_subword_end(
13471        &mut self,
13472        _: &SelectToNextSubwordEnd,
13473        window: &mut Window,
13474        cx: &mut Context<Self>,
13475    ) {
13476        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13477        self.change_selections(Default::default(), window, cx, |s| {
13478            s.move_heads_with(|map, head, _| {
13479                (movement::next_subword_end(map, head), SelectionGoal::None)
13480            });
13481        })
13482    }
13483
13484    pub fn delete_to_next_word_end(
13485        &mut self,
13486        action: &DeleteToNextWordEnd,
13487        window: &mut Window,
13488        cx: &mut Context<Self>,
13489    ) {
13490        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13491        self.transact(window, cx, |this, window, cx| {
13492            this.change_selections(Default::default(), window, cx, |s| {
13493                s.move_with(|map, selection| {
13494                    if selection.is_empty() {
13495                        let mut cursor = if action.ignore_newlines {
13496                            movement::next_word_end(map, selection.head())
13497                        } else {
13498                            movement::next_word_end_or_newline(map, selection.head())
13499                        };
13500                        cursor = movement::adjust_greedy_deletion(
13501                            map,
13502                            selection.head(),
13503                            cursor,
13504                            action.ignore_brackets,
13505                        );
13506                        selection.set_head(cursor, SelectionGoal::None);
13507                    }
13508                });
13509            });
13510            this.insert("", window, cx);
13511        });
13512    }
13513
13514    pub fn delete_to_next_subword_end(
13515        &mut self,
13516        _: &DeleteToNextSubwordEnd,
13517        window: &mut Window,
13518        cx: &mut Context<Self>,
13519    ) {
13520        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13521        self.transact(window, cx, |this, window, cx| {
13522            this.change_selections(Default::default(), window, cx, |s| {
13523                s.move_with(|map, selection| {
13524                    if selection.is_empty() {
13525                        let mut cursor = movement::next_subword_end(map, selection.head());
13526                        cursor =
13527                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13528                        selection.set_head(cursor, SelectionGoal::None);
13529                    }
13530                });
13531            });
13532            this.insert("", window, cx);
13533        });
13534    }
13535
13536    pub fn move_to_beginning_of_line(
13537        &mut self,
13538        action: &MoveToBeginningOfLine,
13539        window: &mut Window,
13540        cx: &mut Context<Self>,
13541    ) {
13542        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13543        self.change_selections(Default::default(), window, cx, |s| {
13544            s.move_cursors_with(|map, head, _| {
13545                (
13546                    movement::indented_line_beginning(
13547                        map,
13548                        head,
13549                        action.stop_at_soft_wraps,
13550                        action.stop_at_indent,
13551                    ),
13552                    SelectionGoal::None,
13553                )
13554            });
13555        })
13556    }
13557
13558    pub fn select_to_beginning_of_line(
13559        &mut self,
13560        action: &SelectToBeginningOfLine,
13561        window: &mut Window,
13562        cx: &mut Context<Self>,
13563    ) {
13564        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13565        self.change_selections(Default::default(), window, cx, |s| {
13566            s.move_heads_with(|map, head, _| {
13567                (
13568                    movement::indented_line_beginning(
13569                        map,
13570                        head,
13571                        action.stop_at_soft_wraps,
13572                        action.stop_at_indent,
13573                    ),
13574                    SelectionGoal::None,
13575                )
13576            });
13577        });
13578    }
13579
13580    pub fn delete_to_beginning_of_line(
13581        &mut self,
13582        action: &DeleteToBeginningOfLine,
13583        window: &mut Window,
13584        cx: &mut Context<Self>,
13585    ) {
13586        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13587        self.transact(window, cx, |this, window, cx| {
13588            this.change_selections(Default::default(), window, cx, |s| {
13589                s.move_with(|_, selection| {
13590                    selection.reversed = true;
13591                });
13592            });
13593
13594            this.select_to_beginning_of_line(
13595                &SelectToBeginningOfLine {
13596                    stop_at_soft_wraps: false,
13597                    stop_at_indent: action.stop_at_indent,
13598                },
13599                window,
13600                cx,
13601            );
13602            this.backspace(&Backspace, window, cx);
13603        });
13604    }
13605
13606    pub fn move_to_end_of_line(
13607        &mut self,
13608        action: &MoveToEndOfLine,
13609        window: &mut Window,
13610        cx: &mut Context<Self>,
13611    ) {
13612        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13613        self.change_selections(Default::default(), window, cx, |s| {
13614            s.move_cursors_with(|map, head, _| {
13615                (
13616                    movement::line_end(map, head, action.stop_at_soft_wraps),
13617                    SelectionGoal::None,
13618                )
13619            });
13620        })
13621    }
13622
13623    pub fn select_to_end_of_line(
13624        &mut self,
13625        action: &SelectToEndOfLine,
13626        window: &mut Window,
13627        cx: &mut Context<Self>,
13628    ) {
13629        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13630        self.change_selections(Default::default(), window, cx, |s| {
13631            s.move_heads_with(|map, head, _| {
13632                (
13633                    movement::line_end(map, head, action.stop_at_soft_wraps),
13634                    SelectionGoal::None,
13635                )
13636            });
13637        })
13638    }
13639
13640    pub fn delete_to_end_of_line(
13641        &mut self,
13642        _: &DeleteToEndOfLine,
13643        window: &mut Window,
13644        cx: &mut Context<Self>,
13645    ) {
13646        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13647        self.transact(window, cx, |this, window, cx| {
13648            this.select_to_end_of_line(
13649                &SelectToEndOfLine {
13650                    stop_at_soft_wraps: false,
13651                },
13652                window,
13653                cx,
13654            );
13655            this.delete(&Delete, window, cx);
13656        });
13657    }
13658
13659    pub fn cut_to_end_of_line(
13660        &mut self,
13661        action: &CutToEndOfLine,
13662        window: &mut Window,
13663        cx: &mut Context<Self>,
13664    ) {
13665        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13666        self.transact(window, cx, |this, window, cx| {
13667            this.select_to_end_of_line(
13668                &SelectToEndOfLine {
13669                    stop_at_soft_wraps: false,
13670                },
13671                window,
13672                cx,
13673            );
13674            if !action.stop_at_newlines {
13675                this.change_selections(Default::default(), window, cx, |s| {
13676                    s.move_with(|_, sel| {
13677                        if sel.is_empty() {
13678                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13679                        }
13680                    });
13681                });
13682            }
13683            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13684            let item = this.cut_common(false, window, cx);
13685            cx.write_to_clipboard(item);
13686        });
13687    }
13688
13689    pub fn move_to_start_of_paragraph(
13690        &mut self,
13691        _: &MoveToStartOfParagraph,
13692        window: &mut Window,
13693        cx: &mut Context<Self>,
13694    ) {
13695        if matches!(self.mode, EditorMode::SingleLine) {
13696            cx.propagate();
13697            return;
13698        }
13699        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13700        self.change_selections(Default::default(), window, cx, |s| {
13701            s.move_with(|map, selection| {
13702                selection.collapse_to(
13703                    movement::start_of_paragraph(map, selection.head(), 1),
13704                    SelectionGoal::None,
13705                )
13706            });
13707        })
13708    }
13709
13710    pub fn move_to_end_of_paragraph(
13711        &mut self,
13712        _: &MoveToEndOfParagraph,
13713        window: &mut Window,
13714        cx: &mut Context<Self>,
13715    ) {
13716        if matches!(self.mode, EditorMode::SingleLine) {
13717            cx.propagate();
13718            return;
13719        }
13720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13721        self.change_selections(Default::default(), window, cx, |s| {
13722            s.move_with(|map, selection| {
13723                selection.collapse_to(
13724                    movement::end_of_paragraph(map, selection.head(), 1),
13725                    SelectionGoal::None,
13726                )
13727            });
13728        })
13729    }
13730
13731    pub fn select_to_start_of_paragraph(
13732        &mut self,
13733        _: &SelectToStartOfParagraph,
13734        window: &mut Window,
13735        cx: &mut Context<Self>,
13736    ) {
13737        if matches!(self.mode, EditorMode::SingleLine) {
13738            cx.propagate();
13739            return;
13740        }
13741        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13742        self.change_selections(Default::default(), window, cx, |s| {
13743            s.move_heads_with(|map, head, _| {
13744                (
13745                    movement::start_of_paragraph(map, head, 1),
13746                    SelectionGoal::None,
13747                )
13748            });
13749        })
13750    }
13751
13752    pub fn select_to_end_of_paragraph(
13753        &mut self,
13754        _: &SelectToEndOfParagraph,
13755        window: &mut Window,
13756        cx: &mut Context<Self>,
13757    ) {
13758        if matches!(self.mode, EditorMode::SingleLine) {
13759            cx.propagate();
13760            return;
13761        }
13762        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13763        self.change_selections(Default::default(), window, cx, |s| {
13764            s.move_heads_with(|map, head, _| {
13765                (
13766                    movement::end_of_paragraph(map, head, 1),
13767                    SelectionGoal::None,
13768                )
13769            });
13770        })
13771    }
13772
13773    pub fn move_to_start_of_excerpt(
13774        &mut self,
13775        _: &MoveToStartOfExcerpt,
13776        window: &mut Window,
13777        cx: &mut Context<Self>,
13778    ) {
13779        if matches!(self.mode, EditorMode::SingleLine) {
13780            cx.propagate();
13781            return;
13782        }
13783        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13784        self.change_selections(Default::default(), window, cx, |s| {
13785            s.move_with(|map, selection| {
13786                selection.collapse_to(
13787                    movement::start_of_excerpt(
13788                        map,
13789                        selection.head(),
13790                        workspace::searchable::Direction::Prev,
13791                    ),
13792                    SelectionGoal::None,
13793                )
13794            });
13795        })
13796    }
13797
13798    pub fn move_to_start_of_next_excerpt(
13799        &mut self,
13800        _: &MoveToStartOfNextExcerpt,
13801        window: &mut Window,
13802        cx: &mut Context<Self>,
13803    ) {
13804        if matches!(self.mode, EditorMode::SingleLine) {
13805            cx.propagate();
13806            return;
13807        }
13808
13809        self.change_selections(Default::default(), window, cx, |s| {
13810            s.move_with(|map, selection| {
13811                selection.collapse_to(
13812                    movement::start_of_excerpt(
13813                        map,
13814                        selection.head(),
13815                        workspace::searchable::Direction::Next,
13816                    ),
13817                    SelectionGoal::None,
13818                )
13819            });
13820        })
13821    }
13822
13823    pub fn move_to_end_of_excerpt(
13824        &mut self,
13825        _: &MoveToEndOfExcerpt,
13826        window: &mut Window,
13827        cx: &mut Context<Self>,
13828    ) {
13829        if matches!(self.mode, EditorMode::SingleLine) {
13830            cx.propagate();
13831            return;
13832        }
13833        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13834        self.change_selections(Default::default(), window, cx, |s| {
13835            s.move_with(|map, selection| {
13836                selection.collapse_to(
13837                    movement::end_of_excerpt(
13838                        map,
13839                        selection.head(),
13840                        workspace::searchable::Direction::Next,
13841                    ),
13842                    SelectionGoal::None,
13843                )
13844            });
13845        })
13846    }
13847
13848    pub fn move_to_end_of_previous_excerpt(
13849        &mut self,
13850        _: &MoveToEndOfPreviousExcerpt,
13851        window: &mut Window,
13852        cx: &mut Context<Self>,
13853    ) {
13854        if matches!(self.mode, EditorMode::SingleLine) {
13855            cx.propagate();
13856            return;
13857        }
13858        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13859        self.change_selections(Default::default(), window, cx, |s| {
13860            s.move_with(|map, selection| {
13861                selection.collapse_to(
13862                    movement::end_of_excerpt(
13863                        map,
13864                        selection.head(),
13865                        workspace::searchable::Direction::Prev,
13866                    ),
13867                    SelectionGoal::None,
13868                )
13869            });
13870        })
13871    }
13872
13873    pub fn select_to_start_of_excerpt(
13874        &mut self,
13875        _: &SelectToStartOfExcerpt,
13876        window: &mut Window,
13877        cx: &mut Context<Self>,
13878    ) {
13879        if matches!(self.mode, EditorMode::SingleLine) {
13880            cx.propagate();
13881            return;
13882        }
13883        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13884        self.change_selections(Default::default(), window, cx, |s| {
13885            s.move_heads_with(|map, head, _| {
13886                (
13887                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13888                    SelectionGoal::None,
13889                )
13890            });
13891        })
13892    }
13893
13894    pub fn select_to_start_of_next_excerpt(
13895        &mut self,
13896        _: &SelectToStartOfNextExcerpt,
13897        window: &mut Window,
13898        cx: &mut Context<Self>,
13899    ) {
13900        if matches!(self.mode, EditorMode::SingleLine) {
13901            cx.propagate();
13902            return;
13903        }
13904        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13905        self.change_selections(Default::default(), window, cx, |s| {
13906            s.move_heads_with(|map, head, _| {
13907                (
13908                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13909                    SelectionGoal::None,
13910                )
13911            });
13912        })
13913    }
13914
13915    pub fn select_to_end_of_excerpt(
13916        &mut self,
13917        _: &SelectToEndOfExcerpt,
13918        window: &mut Window,
13919        cx: &mut Context<Self>,
13920    ) {
13921        if matches!(self.mode, EditorMode::SingleLine) {
13922            cx.propagate();
13923            return;
13924        }
13925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13926        self.change_selections(Default::default(), window, cx, |s| {
13927            s.move_heads_with(|map, head, _| {
13928                (
13929                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13930                    SelectionGoal::None,
13931                )
13932            });
13933        })
13934    }
13935
13936    pub fn select_to_end_of_previous_excerpt(
13937        &mut self,
13938        _: &SelectToEndOfPreviousExcerpt,
13939        window: &mut Window,
13940        cx: &mut Context<Self>,
13941    ) {
13942        if matches!(self.mode, EditorMode::SingleLine) {
13943            cx.propagate();
13944            return;
13945        }
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13947        self.change_selections(Default::default(), window, cx, |s| {
13948            s.move_heads_with(|map, head, _| {
13949                (
13950                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13951                    SelectionGoal::None,
13952                )
13953            });
13954        })
13955    }
13956
13957    pub fn move_to_beginning(
13958        &mut self,
13959        _: &MoveToBeginning,
13960        window: &mut Window,
13961        cx: &mut Context<Self>,
13962    ) {
13963        if matches!(self.mode, EditorMode::SingleLine) {
13964            cx.propagate();
13965            return;
13966        }
13967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13968        self.change_selections(Default::default(), window, cx, |s| {
13969            s.select_ranges(vec![0..0]);
13970        });
13971    }
13972
13973    pub fn select_to_beginning(
13974        &mut self,
13975        _: &SelectToBeginning,
13976        window: &mut Window,
13977        cx: &mut Context<Self>,
13978    ) {
13979        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
13980        selection.set_head(Point::zero(), SelectionGoal::None);
13981        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13982        self.change_selections(Default::default(), window, cx, |s| {
13983            s.select(vec![selection]);
13984        });
13985    }
13986
13987    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13988        if matches!(self.mode, EditorMode::SingleLine) {
13989            cx.propagate();
13990            return;
13991        }
13992        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13993        let cursor = self.buffer.read(cx).read(cx).len();
13994        self.change_selections(Default::default(), window, cx, |s| {
13995            s.select_ranges(vec![cursor..cursor])
13996        });
13997    }
13998
13999    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14000        self.nav_history = nav_history;
14001    }
14002
14003    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14004        self.nav_history.as_ref()
14005    }
14006
14007    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14008        self.push_to_nav_history(
14009            self.selections.newest_anchor().head(),
14010            None,
14011            false,
14012            true,
14013            cx,
14014        );
14015    }
14016
14017    fn push_to_nav_history(
14018        &mut self,
14019        cursor_anchor: Anchor,
14020        new_position: Option<Point>,
14021        is_deactivate: bool,
14022        always: bool,
14023        cx: &mut Context<Self>,
14024    ) {
14025        if let Some(nav_history) = self.nav_history.as_mut() {
14026            let buffer = self.buffer.read(cx).read(cx);
14027            let cursor_position = cursor_anchor.to_point(&buffer);
14028            let scroll_state = self.scroll_manager.anchor();
14029            let scroll_top_row = scroll_state.top_row(&buffer);
14030            drop(buffer);
14031
14032            if let Some(new_position) = new_position {
14033                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14034                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14035                    return;
14036                }
14037            }
14038
14039            nav_history.push(
14040                Some(NavigationData {
14041                    cursor_anchor,
14042                    cursor_position,
14043                    scroll_anchor: scroll_state,
14044                    scroll_top_row,
14045                }),
14046                cx,
14047            );
14048            cx.emit(EditorEvent::PushedToNavHistory {
14049                anchor: cursor_anchor,
14050                is_deactivate,
14051            })
14052        }
14053    }
14054
14055    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14056        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14057        let buffer = self.buffer.read(cx).snapshot(cx);
14058        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14059        selection.set_head(buffer.len(), SelectionGoal::None);
14060        self.change_selections(Default::default(), window, cx, |s| {
14061            s.select(vec![selection]);
14062        });
14063    }
14064
14065    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14066        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14067        let end = self.buffer.read(cx).read(cx).len();
14068        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14069            s.select_ranges(vec![0..end]);
14070        });
14071    }
14072
14073    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14074        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14075        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14076        let mut selections = self.selections.all::<Point>(&display_map);
14077        let max_point = display_map.buffer_snapshot().max_point();
14078        for selection in &mut selections {
14079            let rows = selection.spanned_rows(true, &display_map);
14080            selection.start = Point::new(rows.start.0, 0);
14081            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14082            selection.reversed = false;
14083        }
14084        self.change_selections(Default::default(), window, cx, |s| {
14085            s.select(selections);
14086        });
14087    }
14088
14089    pub fn split_selection_into_lines(
14090        &mut self,
14091        action: &SplitSelectionIntoLines,
14092        window: &mut Window,
14093        cx: &mut Context<Self>,
14094    ) {
14095        let selections = self
14096            .selections
14097            .all::<Point>(&self.display_snapshot(cx))
14098            .into_iter()
14099            .map(|selection| selection.start..selection.end)
14100            .collect::<Vec<_>>();
14101        self.unfold_ranges(&selections, true, true, cx);
14102
14103        let mut new_selection_ranges = Vec::new();
14104        {
14105            let buffer = self.buffer.read(cx).read(cx);
14106            for selection in selections {
14107                for row in selection.start.row..selection.end.row {
14108                    let line_start = Point::new(row, 0);
14109                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14110
14111                    if action.keep_selections {
14112                        // Keep the selection range for each line
14113                        let selection_start = if row == selection.start.row {
14114                            selection.start
14115                        } else {
14116                            line_start
14117                        };
14118                        new_selection_ranges.push(selection_start..line_end);
14119                    } else {
14120                        // Collapse to cursor at end of line
14121                        new_selection_ranges.push(line_end..line_end);
14122                    }
14123                }
14124
14125                let is_multiline_selection = selection.start.row != selection.end.row;
14126                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14127                // so this action feels more ergonomic when paired with other selection operations
14128                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14129                if !should_skip_last {
14130                    if action.keep_selections {
14131                        if is_multiline_selection {
14132                            let line_start = Point::new(selection.end.row, 0);
14133                            new_selection_ranges.push(line_start..selection.end);
14134                        } else {
14135                            new_selection_ranges.push(selection.start..selection.end);
14136                        }
14137                    } else {
14138                        new_selection_ranges.push(selection.end..selection.end);
14139                    }
14140                }
14141            }
14142        }
14143        self.change_selections(Default::default(), window, cx, |s| {
14144            s.select_ranges(new_selection_ranges);
14145        });
14146    }
14147
14148    pub fn add_selection_above(
14149        &mut self,
14150        action: &AddSelectionAbove,
14151        window: &mut Window,
14152        cx: &mut Context<Self>,
14153    ) {
14154        self.add_selection(true, action.skip_soft_wrap, window, cx);
14155    }
14156
14157    pub fn add_selection_below(
14158        &mut self,
14159        action: &AddSelectionBelow,
14160        window: &mut Window,
14161        cx: &mut Context<Self>,
14162    ) {
14163        self.add_selection(false, action.skip_soft_wrap, window, cx);
14164    }
14165
14166    fn add_selection(
14167        &mut self,
14168        above: bool,
14169        skip_soft_wrap: bool,
14170        window: &mut Window,
14171        cx: &mut Context<Self>,
14172    ) {
14173        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14174
14175        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14176        let all_selections = self.selections.all::<Point>(&display_map);
14177        let text_layout_details = self.text_layout_details(window);
14178
14179        let (mut columnar_selections, new_selections_to_columnarize) = {
14180            if let Some(state) = self.add_selections_state.as_ref() {
14181                let columnar_selection_ids: HashSet<_> = state
14182                    .groups
14183                    .iter()
14184                    .flat_map(|group| group.stack.iter())
14185                    .copied()
14186                    .collect();
14187
14188                all_selections
14189                    .into_iter()
14190                    .partition(|s| columnar_selection_ids.contains(&s.id))
14191            } else {
14192                (Vec::new(), all_selections)
14193            }
14194        };
14195
14196        let mut state = self
14197            .add_selections_state
14198            .take()
14199            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14200
14201        for selection in new_selections_to_columnarize {
14202            let range = selection.display_range(&display_map).sorted();
14203            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14204            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14205            let positions = start_x.min(end_x)..start_x.max(end_x);
14206            let mut stack = Vec::new();
14207            for row in range.start.row().0..=range.end.row().0 {
14208                if let Some(selection) = self.selections.build_columnar_selection(
14209                    &display_map,
14210                    DisplayRow(row),
14211                    &positions,
14212                    selection.reversed,
14213                    &text_layout_details,
14214                ) {
14215                    stack.push(selection.id);
14216                    columnar_selections.push(selection);
14217                }
14218            }
14219            if !stack.is_empty() {
14220                if above {
14221                    stack.reverse();
14222                }
14223                state.groups.push(AddSelectionsGroup { above, stack });
14224            }
14225        }
14226
14227        let mut final_selections = Vec::new();
14228        let end_row = if above {
14229            DisplayRow(0)
14230        } else {
14231            display_map.max_point().row()
14232        };
14233
14234        let mut last_added_item_per_group = HashMap::default();
14235        for group in state.groups.iter_mut() {
14236            if let Some(last_id) = group.stack.last() {
14237                last_added_item_per_group.insert(*last_id, group);
14238            }
14239        }
14240
14241        for selection in columnar_selections {
14242            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14243                if above == group.above {
14244                    let range = selection.display_range(&display_map).sorted();
14245                    debug_assert_eq!(range.start.row(), range.end.row());
14246                    let mut row = range.start.row();
14247                    let positions =
14248                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14249                            Pixels::from(start)..Pixels::from(end)
14250                        } else {
14251                            let start_x =
14252                                display_map.x_for_display_point(range.start, &text_layout_details);
14253                            let end_x =
14254                                display_map.x_for_display_point(range.end, &text_layout_details);
14255                            start_x.min(end_x)..start_x.max(end_x)
14256                        };
14257
14258                    let mut maybe_new_selection = None;
14259                    let direction = if above { -1 } else { 1 };
14260
14261                    while row != end_row {
14262                        if skip_soft_wrap {
14263                            row = display_map
14264                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14265                                .row();
14266                        } else if above {
14267                            row.0 -= 1;
14268                        } else {
14269                            row.0 += 1;
14270                        }
14271
14272                        if let Some(new_selection) = self.selections.build_columnar_selection(
14273                            &display_map,
14274                            row,
14275                            &positions,
14276                            selection.reversed,
14277                            &text_layout_details,
14278                        ) {
14279                            maybe_new_selection = Some(new_selection);
14280                            break;
14281                        }
14282                    }
14283
14284                    if let Some(new_selection) = maybe_new_selection {
14285                        group.stack.push(new_selection.id);
14286                        if above {
14287                            final_selections.push(new_selection);
14288                            final_selections.push(selection);
14289                        } else {
14290                            final_selections.push(selection);
14291                            final_selections.push(new_selection);
14292                        }
14293                    } else {
14294                        final_selections.push(selection);
14295                    }
14296                } else {
14297                    group.stack.pop();
14298                }
14299            } else {
14300                final_selections.push(selection);
14301            }
14302        }
14303
14304        self.change_selections(Default::default(), window, cx, |s| {
14305            s.select(final_selections);
14306        });
14307
14308        let final_selection_ids: HashSet<_> = self
14309            .selections
14310            .all::<Point>(&display_map)
14311            .iter()
14312            .map(|s| s.id)
14313            .collect();
14314        state.groups.retain_mut(|group| {
14315            // selections might get merged above so we remove invalid items from stacks
14316            group.stack.retain(|id| final_selection_ids.contains(id));
14317
14318            // single selection in stack can be treated as initial state
14319            group.stack.len() > 1
14320        });
14321
14322        if !state.groups.is_empty() {
14323            self.add_selections_state = Some(state);
14324        }
14325    }
14326
14327    fn select_match_ranges(
14328        &mut self,
14329        range: Range<usize>,
14330        reversed: bool,
14331        replace_newest: bool,
14332        auto_scroll: Option<Autoscroll>,
14333        window: &mut Window,
14334        cx: &mut Context<Editor>,
14335    ) {
14336        self.unfold_ranges(
14337            std::slice::from_ref(&range),
14338            false,
14339            auto_scroll.is_some(),
14340            cx,
14341        );
14342        let effects = if let Some(scroll) = auto_scroll {
14343            SelectionEffects::scroll(scroll)
14344        } else {
14345            SelectionEffects::no_scroll()
14346        };
14347        self.change_selections(effects, window, cx, |s| {
14348            if replace_newest {
14349                s.delete(s.newest_anchor().id);
14350            }
14351            if reversed {
14352                s.insert_range(range.end..range.start);
14353            } else {
14354                s.insert_range(range);
14355            }
14356        });
14357    }
14358
14359    pub fn select_next_match_internal(
14360        &mut self,
14361        display_map: &DisplaySnapshot,
14362        replace_newest: bool,
14363        autoscroll: Option<Autoscroll>,
14364        window: &mut Window,
14365        cx: &mut Context<Self>,
14366    ) -> Result<()> {
14367        let buffer = display_map.buffer_snapshot();
14368        let mut selections = self.selections.all::<usize>(&display_map);
14369        if let Some(mut select_next_state) = self.select_next_state.take() {
14370            let query = &select_next_state.query;
14371            if !select_next_state.done {
14372                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14373                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14374                let mut next_selected_range = None;
14375
14376                let bytes_after_last_selection =
14377                    buffer.bytes_in_range(last_selection.end..buffer.len());
14378                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14379                let query_matches = query
14380                    .stream_find_iter(bytes_after_last_selection)
14381                    .map(|result| (last_selection.end, result))
14382                    .chain(
14383                        query
14384                            .stream_find_iter(bytes_before_first_selection)
14385                            .map(|result| (0, result)),
14386                    );
14387
14388                for (start_offset, query_match) in query_matches {
14389                    let query_match = query_match.unwrap(); // can only fail due to I/O
14390                    let offset_range =
14391                        start_offset + query_match.start()..start_offset + query_match.end();
14392
14393                    if !select_next_state.wordwise
14394                        || (!buffer.is_inside_word(offset_range.start, None)
14395                            && !buffer.is_inside_word(offset_range.end, None))
14396                    {
14397                        let idx = selections
14398                            .partition_point(|selection| selection.end <= offset_range.start);
14399                        let overlaps = selections
14400                            .get(idx)
14401                            .map_or(false, |selection| selection.start < offset_range.end);
14402
14403                        if !overlaps {
14404                            next_selected_range = Some(offset_range);
14405                            break;
14406                        }
14407                    }
14408                }
14409
14410                if let Some(next_selected_range) = next_selected_range {
14411                    self.select_match_ranges(
14412                        next_selected_range,
14413                        last_selection.reversed,
14414                        replace_newest,
14415                        autoscroll,
14416                        window,
14417                        cx,
14418                    );
14419                } else {
14420                    select_next_state.done = true;
14421                }
14422            }
14423
14424            self.select_next_state = Some(select_next_state);
14425        } else {
14426            let mut only_carets = true;
14427            let mut same_text_selected = true;
14428            let mut selected_text = None;
14429
14430            let mut selections_iter = selections.iter().peekable();
14431            while let Some(selection) = selections_iter.next() {
14432                if selection.start != selection.end {
14433                    only_carets = false;
14434                }
14435
14436                if same_text_selected {
14437                    if selected_text.is_none() {
14438                        selected_text =
14439                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14440                    }
14441
14442                    if let Some(next_selection) = selections_iter.peek() {
14443                        if next_selection.range().len() == selection.range().len() {
14444                            let next_selected_text = buffer
14445                                .text_for_range(next_selection.range())
14446                                .collect::<String>();
14447                            if Some(next_selected_text) != selected_text {
14448                                same_text_selected = false;
14449                                selected_text = None;
14450                            }
14451                        } else {
14452                            same_text_selected = false;
14453                            selected_text = None;
14454                        }
14455                    }
14456                }
14457            }
14458
14459            if only_carets {
14460                for selection in &mut selections {
14461                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14462                    selection.start = word_range.start;
14463                    selection.end = word_range.end;
14464                    selection.goal = SelectionGoal::None;
14465                    selection.reversed = false;
14466                    self.select_match_ranges(
14467                        selection.start..selection.end,
14468                        selection.reversed,
14469                        replace_newest,
14470                        autoscroll,
14471                        window,
14472                        cx,
14473                    );
14474                }
14475
14476                if selections.len() == 1 {
14477                    let selection = selections
14478                        .last()
14479                        .expect("ensured that there's only one selection");
14480                    let query = buffer
14481                        .text_for_range(selection.start..selection.end)
14482                        .collect::<String>();
14483                    let is_empty = query.is_empty();
14484                    let select_state = SelectNextState {
14485                        query: AhoCorasick::new(&[query])?,
14486                        wordwise: true,
14487                        done: is_empty,
14488                    };
14489                    self.select_next_state = Some(select_state);
14490                } else {
14491                    self.select_next_state = None;
14492                }
14493            } else if let Some(selected_text) = selected_text {
14494                self.select_next_state = Some(SelectNextState {
14495                    query: AhoCorasick::new(&[selected_text])?,
14496                    wordwise: false,
14497                    done: false,
14498                });
14499                self.select_next_match_internal(
14500                    display_map,
14501                    replace_newest,
14502                    autoscroll,
14503                    window,
14504                    cx,
14505                )?;
14506            }
14507        }
14508        Ok(())
14509    }
14510
14511    pub fn select_all_matches(
14512        &mut self,
14513        _action: &SelectAllMatches,
14514        window: &mut Window,
14515        cx: &mut Context<Self>,
14516    ) -> Result<()> {
14517        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14518
14519        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14520
14521        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14522        let Some(select_next_state) = self.select_next_state.as_mut() else {
14523            return Ok(());
14524        };
14525        if select_next_state.done {
14526            return Ok(());
14527        }
14528
14529        let mut new_selections = Vec::new();
14530
14531        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14532        let buffer = display_map.buffer_snapshot();
14533        let query_matches = select_next_state
14534            .query
14535            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14536
14537        for query_match in query_matches.into_iter() {
14538            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14539            let offset_range = if reversed {
14540                query_match.end()..query_match.start()
14541            } else {
14542                query_match.start()..query_match.end()
14543            };
14544
14545            if !select_next_state.wordwise
14546                || (!buffer.is_inside_word(offset_range.start, None)
14547                    && !buffer.is_inside_word(offset_range.end, None))
14548            {
14549                new_selections.push(offset_range.start..offset_range.end);
14550            }
14551        }
14552
14553        select_next_state.done = true;
14554
14555        if new_selections.is_empty() {
14556            log::error!("bug: new_selections is empty in select_all_matches");
14557            return Ok(());
14558        }
14559
14560        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14561        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14562            selections.select_ranges(new_selections)
14563        });
14564
14565        Ok(())
14566    }
14567
14568    pub fn select_next(
14569        &mut self,
14570        action: &SelectNext,
14571        window: &mut Window,
14572        cx: &mut Context<Self>,
14573    ) -> Result<()> {
14574        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14575        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14576        self.select_next_match_internal(
14577            &display_map,
14578            action.replace_newest,
14579            Some(Autoscroll::newest()),
14580            window,
14581            cx,
14582        )?;
14583        Ok(())
14584    }
14585
14586    pub fn select_previous(
14587        &mut self,
14588        action: &SelectPrevious,
14589        window: &mut Window,
14590        cx: &mut Context<Self>,
14591    ) -> Result<()> {
14592        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14593        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14594        let buffer = display_map.buffer_snapshot();
14595        let mut selections = self.selections.all::<usize>(&display_map);
14596        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14597            let query = &select_prev_state.query;
14598            if !select_prev_state.done {
14599                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14600                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14601                let mut next_selected_range = None;
14602                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14603                let bytes_before_last_selection =
14604                    buffer.reversed_bytes_in_range(0..last_selection.start);
14605                let bytes_after_first_selection =
14606                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14607                let query_matches = query
14608                    .stream_find_iter(bytes_before_last_selection)
14609                    .map(|result| (last_selection.start, result))
14610                    .chain(
14611                        query
14612                            .stream_find_iter(bytes_after_first_selection)
14613                            .map(|result| (buffer.len(), result)),
14614                    );
14615                for (end_offset, query_match) in query_matches {
14616                    let query_match = query_match.unwrap(); // can only fail due to I/O
14617                    let offset_range =
14618                        end_offset - query_match.end()..end_offset - query_match.start();
14619
14620                    if !select_prev_state.wordwise
14621                        || (!buffer.is_inside_word(offset_range.start, None)
14622                            && !buffer.is_inside_word(offset_range.end, None))
14623                    {
14624                        next_selected_range = Some(offset_range);
14625                        break;
14626                    }
14627                }
14628
14629                if let Some(next_selected_range) = next_selected_range {
14630                    self.select_match_ranges(
14631                        next_selected_range,
14632                        last_selection.reversed,
14633                        action.replace_newest,
14634                        Some(Autoscroll::newest()),
14635                        window,
14636                        cx,
14637                    );
14638                } else {
14639                    select_prev_state.done = true;
14640                }
14641            }
14642
14643            self.select_prev_state = Some(select_prev_state);
14644        } else {
14645            let mut only_carets = true;
14646            let mut same_text_selected = true;
14647            let mut selected_text = None;
14648
14649            let mut selections_iter = selections.iter().peekable();
14650            while let Some(selection) = selections_iter.next() {
14651                if selection.start != selection.end {
14652                    only_carets = false;
14653                }
14654
14655                if same_text_selected {
14656                    if selected_text.is_none() {
14657                        selected_text =
14658                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14659                    }
14660
14661                    if let Some(next_selection) = selections_iter.peek() {
14662                        if next_selection.range().len() == selection.range().len() {
14663                            let next_selected_text = buffer
14664                                .text_for_range(next_selection.range())
14665                                .collect::<String>();
14666                            if Some(next_selected_text) != selected_text {
14667                                same_text_selected = false;
14668                                selected_text = None;
14669                            }
14670                        } else {
14671                            same_text_selected = false;
14672                            selected_text = None;
14673                        }
14674                    }
14675                }
14676            }
14677
14678            if only_carets {
14679                for selection in &mut selections {
14680                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14681                    selection.start = word_range.start;
14682                    selection.end = word_range.end;
14683                    selection.goal = SelectionGoal::None;
14684                    selection.reversed = false;
14685                    self.select_match_ranges(
14686                        selection.start..selection.end,
14687                        selection.reversed,
14688                        action.replace_newest,
14689                        Some(Autoscroll::newest()),
14690                        window,
14691                        cx,
14692                    );
14693                }
14694                if selections.len() == 1 {
14695                    let selection = selections
14696                        .last()
14697                        .expect("ensured that there's only one selection");
14698                    let query = buffer
14699                        .text_for_range(selection.start..selection.end)
14700                        .collect::<String>();
14701                    let is_empty = query.is_empty();
14702                    let select_state = SelectNextState {
14703                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14704                        wordwise: true,
14705                        done: is_empty,
14706                    };
14707                    self.select_prev_state = Some(select_state);
14708                } else {
14709                    self.select_prev_state = None;
14710                }
14711            } else if let Some(selected_text) = selected_text {
14712                self.select_prev_state = Some(SelectNextState {
14713                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14714                    wordwise: false,
14715                    done: false,
14716                });
14717                self.select_previous(action, window, cx)?;
14718            }
14719        }
14720        Ok(())
14721    }
14722
14723    pub fn find_next_match(
14724        &mut self,
14725        _: &FindNextMatch,
14726        window: &mut Window,
14727        cx: &mut Context<Self>,
14728    ) -> Result<()> {
14729        let selections = self.selections.disjoint_anchors_arc();
14730        match selections.first() {
14731            Some(first) if selections.len() >= 2 => {
14732                self.change_selections(Default::default(), window, cx, |s| {
14733                    s.select_ranges([first.range()]);
14734                });
14735            }
14736            _ => self.select_next(
14737                &SelectNext {
14738                    replace_newest: true,
14739                },
14740                window,
14741                cx,
14742            )?,
14743        }
14744        Ok(())
14745    }
14746
14747    pub fn find_previous_match(
14748        &mut self,
14749        _: &FindPreviousMatch,
14750        window: &mut Window,
14751        cx: &mut Context<Self>,
14752    ) -> Result<()> {
14753        let selections = self.selections.disjoint_anchors_arc();
14754        match selections.last() {
14755            Some(last) if selections.len() >= 2 => {
14756                self.change_selections(Default::default(), window, cx, |s| {
14757                    s.select_ranges([last.range()]);
14758                });
14759            }
14760            _ => self.select_previous(
14761                &SelectPrevious {
14762                    replace_newest: true,
14763                },
14764                window,
14765                cx,
14766            )?,
14767        }
14768        Ok(())
14769    }
14770
14771    pub fn toggle_comments(
14772        &mut self,
14773        action: &ToggleComments,
14774        window: &mut Window,
14775        cx: &mut Context<Self>,
14776    ) {
14777        if self.read_only(cx) {
14778            return;
14779        }
14780        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14781        let text_layout_details = &self.text_layout_details(window);
14782        self.transact(window, cx, |this, window, cx| {
14783            let mut selections = this
14784                .selections
14785                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14786            let mut edits = Vec::new();
14787            let mut selection_edit_ranges = Vec::new();
14788            let mut last_toggled_row = None;
14789            let snapshot = this.buffer.read(cx).read(cx);
14790            let empty_str: Arc<str> = Arc::default();
14791            let mut suffixes_inserted = Vec::new();
14792            let ignore_indent = action.ignore_indent;
14793
14794            fn comment_prefix_range(
14795                snapshot: &MultiBufferSnapshot,
14796                row: MultiBufferRow,
14797                comment_prefix: &str,
14798                comment_prefix_whitespace: &str,
14799                ignore_indent: bool,
14800            ) -> Range<Point> {
14801                let indent_size = if ignore_indent {
14802                    0
14803                } else {
14804                    snapshot.indent_size_for_line(row).len
14805                };
14806
14807                let start = Point::new(row.0, indent_size);
14808
14809                let mut line_bytes = snapshot
14810                    .bytes_in_range(start..snapshot.max_point())
14811                    .flatten()
14812                    .copied();
14813
14814                // If this line currently begins with the line comment prefix, then record
14815                // the range containing the prefix.
14816                if line_bytes
14817                    .by_ref()
14818                    .take(comment_prefix.len())
14819                    .eq(comment_prefix.bytes())
14820                {
14821                    // Include any whitespace that matches the comment prefix.
14822                    let matching_whitespace_len = line_bytes
14823                        .zip(comment_prefix_whitespace.bytes())
14824                        .take_while(|(a, b)| a == b)
14825                        .count() as u32;
14826                    let end = Point::new(
14827                        start.row,
14828                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14829                    );
14830                    start..end
14831                } else {
14832                    start..start
14833                }
14834            }
14835
14836            fn comment_suffix_range(
14837                snapshot: &MultiBufferSnapshot,
14838                row: MultiBufferRow,
14839                comment_suffix: &str,
14840                comment_suffix_has_leading_space: bool,
14841            ) -> Range<Point> {
14842                let end = Point::new(row.0, snapshot.line_len(row));
14843                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14844
14845                let mut line_end_bytes = snapshot
14846                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14847                    .flatten()
14848                    .copied();
14849
14850                let leading_space_len = if suffix_start_column > 0
14851                    && line_end_bytes.next() == Some(b' ')
14852                    && comment_suffix_has_leading_space
14853                {
14854                    1
14855                } else {
14856                    0
14857                };
14858
14859                // If this line currently begins with the line comment prefix, then record
14860                // the range containing the prefix.
14861                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14862                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14863                    start..end
14864                } else {
14865                    end..end
14866                }
14867            }
14868
14869            // TODO: Handle selections that cross excerpts
14870            for selection in &mut selections {
14871                let start_column = snapshot
14872                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14873                    .len;
14874                let language = if let Some(language) =
14875                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14876                {
14877                    language
14878                } else {
14879                    continue;
14880                };
14881
14882                selection_edit_ranges.clear();
14883
14884                // If multiple selections contain a given row, avoid processing that
14885                // row more than once.
14886                let mut start_row = MultiBufferRow(selection.start.row);
14887                if last_toggled_row == Some(start_row) {
14888                    start_row = start_row.next_row();
14889                }
14890                let end_row =
14891                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14892                        MultiBufferRow(selection.end.row - 1)
14893                    } else {
14894                        MultiBufferRow(selection.end.row)
14895                    };
14896                last_toggled_row = Some(end_row);
14897
14898                if start_row > end_row {
14899                    continue;
14900                }
14901
14902                // If the language has line comments, toggle those.
14903                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14904
14905                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14906                if ignore_indent {
14907                    full_comment_prefixes = full_comment_prefixes
14908                        .into_iter()
14909                        .map(|s| Arc::from(s.trim_end()))
14910                        .collect();
14911                }
14912
14913                if !full_comment_prefixes.is_empty() {
14914                    let first_prefix = full_comment_prefixes
14915                        .first()
14916                        .expect("prefixes is non-empty");
14917                    let prefix_trimmed_lengths = full_comment_prefixes
14918                        .iter()
14919                        .map(|p| p.trim_end_matches(' ').len())
14920                        .collect::<SmallVec<[usize; 4]>>();
14921
14922                    let mut all_selection_lines_are_comments = true;
14923
14924                    for row in start_row.0..=end_row.0 {
14925                        let row = MultiBufferRow(row);
14926                        if start_row < end_row && snapshot.is_line_blank(row) {
14927                            continue;
14928                        }
14929
14930                        let prefix_range = full_comment_prefixes
14931                            .iter()
14932                            .zip(prefix_trimmed_lengths.iter().copied())
14933                            .map(|(prefix, trimmed_prefix_len)| {
14934                                comment_prefix_range(
14935                                    snapshot.deref(),
14936                                    row,
14937                                    &prefix[..trimmed_prefix_len],
14938                                    &prefix[trimmed_prefix_len..],
14939                                    ignore_indent,
14940                                )
14941                            })
14942                            .max_by_key(|range| range.end.column - range.start.column)
14943                            .expect("prefixes is non-empty");
14944
14945                        if prefix_range.is_empty() {
14946                            all_selection_lines_are_comments = false;
14947                        }
14948
14949                        selection_edit_ranges.push(prefix_range);
14950                    }
14951
14952                    if all_selection_lines_are_comments {
14953                        edits.extend(
14954                            selection_edit_ranges
14955                                .iter()
14956                                .cloned()
14957                                .map(|range| (range, empty_str.clone())),
14958                        );
14959                    } else {
14960                        let min_column = selection_edit_ranges
14961                            .iter()
14962                            .map(|range| range.start.column)
14963                            .min()
14964                            .unwrap_or(0);
14965                        edits.extend(selection_edit_ranges.iter().map(|range| {
14966                            let position = Point::new(range.start.row, min_column);
14967                            (position..position, first_prefix.clone())
14968                        }));
14969                    }
14970                } else if let Some(BlockCommentConfig {
14971                    start: full_comment_prefix,
14972                    end: comment_suffix,
14973                    ..
14974                }) = language.block_comment()
14975                {
14976                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14977                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14978                    let prefix_range = comment_prefix_range(
14979                        snapshot.deref(),
14980                        start_row,
14981                        comment_prefix,
14982                        comment_prefix_whitespace,
14983                        ignore_indent,
14984                    );
14985                    let suffix_range = comment_suffix_range(
14986                        snapshot.deref(),
14987                        end_row,
14988                        comment_suffix.trim_start_matches(' '),
14989                        comment_suffix.starts_with(' '),
14990                    );
14991
14992                    if prefix_range.is_empty() || suffix_range.is_empty() {
14993                        edits.push((
14994                            prefix_range.start..prefix_range.start,
14995                            full_comment_prefix.clone(),
14996                        ));
14997                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14998                        suffixes_inserted.push((end_row, comment_suffix.len()));
14999                    } else {
15000                        edits.push((prefix_range, empty_str.clone()));
15001                        edits.push((suffix_range, empty_str.clone()));
15002                    }
15003                } else {
15004                    continue;
15005                }
15006            }
15007
15008            drop(snapshot);
15009            this.buffer.update(cx, |buffer, cx| {
15010                buffer.edit(edits, None, cx);
15011            });
15012
15013            // Adjust selections so that they end before any comment suffixes that
15014            // were inserted.
15015            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15016            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15017            let snapshot = this.buffer.read(cx).read(cx);
15018            for selection in &mut selections {
15019                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15020                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15021                        Ordering::Less => {
15022                            suffixes_inserted.next();
15023                            continue;
15024                        }
15025                        Ordering::Greater => break,
15026                        Ordering::Equal => {
15027                            if selection.end.column == snapshot.line_len(row) {
15028                                if selection.is_empty() {
15029                                    selection.start.column -= suffix_len as u32;
15030                                }
15031                                selection.end.column -= suffix_len as u32;
15032                            }
15033                            break;
15034                        }
15035                    }
15036                }
15037            }
15038
15039            drop(snapshot);
15040            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15041
15042            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15043            let selections_on_single_row = selections.windows(2).all(|selections| {
15044                selections[0].start.row == selections[1].start.row
15045                    && selections[0].end.row == selections[1].end.row
15046                    && selections[0].start.row == selections[0].end.row
15047            });
15048            let selections_selecting = selections
15049                .iter()
15050                .any(|selection| selection.start != selection.end);
15051            let advance_downwards = action.advance_downwards
15052                && selections_on_single_row
15053                && !selections_selecting
15054                && !matches!(this.mode, EditorMode::SingleLine);
15055
15056            if advance_downwards {
15057                let snapshot = this.buffer.read(cx).snapshot(cx);
15058
15059                this.change_selections(Default::default(), window, cx, |s| {
15060                    s.move_cursors_with(|display_snapshot, display_point, _| {
15061                        let mut point = display_point.to_point(display_snapshot);
15062                        point.row += 1;
15063                        point = snapshot.clip_point(point, Bias::Left);
15064                        let display_point = point.to_display_point(display_snapshot);
15065                        let goal = SelectionGoal::HorizontalPosition(
15066                            display_snapshot
15067                                .x_for_display_point(display_point, text_layout_details)
15068                                .into(),
15069                        );
15070                        (display_point, goal)
15071                    })
15072                });
15073            }
15074        });
15075    }
15076
15077    pub fn select_enclosing_symbol(
15078        &mut self,
15079        _: &SelectEnclosingSymbol,
15080        window: &mut Window,
15081        cx: &mut Context<Self>,
15082    ) {
15083        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15084
15085        let buffer = self.buffer.read(cx).snapshot(cx);
15086        let old_selections = self
15087            .selections
15088            .all::<usize>(&self.display_snapshot(cx))
15089            .into_boxed_slice();
15090
15091        fn update_selection(
15092            selection: &Selection<usize>,
15093            buffer_snap: &MultiBufferSnapshot,
15094        ) -> Option<Selection<usize>> {
15095            let cursor = selection.head();
15096            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15097            for symbol in symbols.iter().rev() {
15098                let start = symbol.range.start.to_offset(buffer_snap);
15099                let end = symbol.range.end.to_offset(buffer_snap);
15100                let new_range = start..end;
15101                if start < selection.start || end > selection.end {
15102                    return Some(Selection {
15103                        id: selection.id,
15104                        start: new_range.start,
15105                        end: new_range.end,
15106                        goal: SelectionGoal::None,
15107                        reversed: selection.reversed,
15108                    });
15109                }
15110            }
15111            None
15112        }
15113
15114        let mut selected_larger_symbol = false;
15115        let new_selections = old_selections
15116            .iter()
15117            .map(|selection| match update_selection(selection, &buffer) {
15118                Some(new_selection) => {
15119                    if new_selection.range() != selection.range() {
15120                        selected_larger_symbol = true;
15121                    }
15122                    new_selection
15123                }
15124                None => selection.clone(),
15125            })
15126            .collect::<Vec<_>>();
15127
15128        if selected_larger_symbol {
15129            self.change_selections(Default::default(), window, cx, |s| {
15130                s.select(new_selections);
15131            });
15132        }
15133    }
15134
15135    pub fn select_larger_syntax_node(
15136        &mut self,
15137        _: &SelectLargerSyntaxNode,
15138        window: &mut Window,
15139        cx: &mut Context<Self>,
15140    ) {
15141        let Some(visible_row_count) = self.visible_row_count() else {
15142            return;
15143        };
15144        let old_selections: Box<[_]> = self
15145            .selections
15146            .all::<usize>(&self.display_snapshot(cx))
15147            .into();
15148        if old_selections.is_empty() {
15149            return;
15150        }
15151
15152        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15153
15154        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15155        let buffer = self.buffer.read(cx).snapshot(cx);
15156
15157        let mut selected_larger_node = false;
15158        let mut new_selections = old_selections
15159            .iter()
15160            .map(|selection| {
15161                let old_range = selection.start..selection.end;
15162
15163                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15164                    // manually select word at selection
15165                    if ["string_content", "inline"].contains(&node.kind()) {
15166                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15167                        // ignore if word is already selected
15168                        if !word_range.is_empty() && old_range != word_range {
15169                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15170                            // only select word if start and end point belongs to same word
15171                            if word_range == last_word_range {
15172                                selected_larger_node = true;
15173                                return Selection {
15174                                    id: selection.id,
15175                                    start: word_range.start,
15176                                    end: word_range.end,
15177                                    goal: SelectionGoal::None,
15178                                    reversed: selection.reversed,
15179                                };
15180                            }
15181                        }
15182                    }
15183                }
15184
15185                let mut new_range = old_range.clone();
15186                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15187                    new_range = range;
15188                    if !node.is_named() {
15189                        continue;
15190                    }
15191                    if !display_map.intersects_fold(new_range.start)
15192                        && !display_map.intersects_fold(new_range.end)
15193                    {
15194                        break;
15195                    }
15196                }
15197
15198                selected_larger_node |= new_range != old_range;
15199                Selection {
15200                    id: selection.id,
15201                    start: new_range.start,
15202                    end: new_range.end,
15203                    goal: SelectionGoal::None,
15204                    reversed: selection.reversed,
15205                }
15206            })
15207            .collect::<Vec<_>>();
15208
15209        if !selected_larger_node {
15210            return; // don't put this call in the history
15211        }
15212
15213        // scroll based on transformation done to the last selection created by the user
15214        let (last_old, last_new) = old_selections
15215            .last()
15216            .zip(new_selections.last().cloned())
15217            .expect("old_selections isn't empty");
15218
15219        // revert selection
15220        let is_selection_reversed = {
15221            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15222            new_selections.last_mut().expect("checked above").reversed =
15223                should_newest_selection_be_reversed;
15224            should_newest_selection_be_reversed
15225        };
15226
15227        if selected_larger_node {
15228            self.select_syntax_node_history.disable_clearing = true;
15229            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15230                s.select(new_selections.clone());
15231            });
15232            self.select_syntax_node_history.disable_clearing = false;
15233        }
15234
15235        let start_row = last_new.start.to_display_point(&display_map).row().0;
15236        let end_row = last_new.end.to_display_point(&display_map).row().0;
15237        let selection_height = end_row - start_row + 1;
15238        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15239
15240        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15241        let scroll_behavior = if fits_on_the_screen {
15242            self.request_autoscroll(Autoscroll::fit(), cx);
15243            SelectSyntaxNodeScrollBehavior::FitSelection
15244        } else if is_selection_reversed {
15245            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15246            SelectSyntaxNodeScrollBehavior::CursorTop
15247        } else {
15248            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15249            SelectSyntaxNodeScrollBehavior::CursorBottom
15250        };
15251
15252        self.select_syntax_node_history.push((
15253            old_selections,
15254            scroll_behavior,
15255            is_selection_reversed,
15256        ));
15257    }
15258
15259    pub fn select_smaller_syntax_node(
15260        &mut self,
15261        _: &SelectSmallerSyntaxNode,
15262        window: &mut Window,
15263        cx: &mut Context<Self>,
15264    ) {
15265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15266
15267        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15268            self.select_syntax_node_history.pop()
15269        {
15270            if let Some(selection) = selections.last_mut() {
15271                selection.reversed = is_selection_reversed;
15272            }
15273
15274            self.select_syntax_node_history.disable_clearing = true;
15275            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15276                s.select(selections.to_vec());
15277            });
15278            self.select_syntax_node_history.disable_clearing = false;
15279
15280            match scroll_behavior {
15281                SelectSyntaxNodeScrollBehavior::CursorTop => {
15282                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15283                }
15284                SelectSyntaxNodeScrollBehavior::FitSelection => {
15285                    self.request_autoscroll(Autoscroll::fit(), cx);
15286                }
15287                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15288                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15289                }
15290            }
15291        }
15292    }
15293
15294    pub fn unwrap_syntax_node(
15295        &mut self,
15296        _: &UnwrapSyntaxNode,
15297        window: &mut Window,
15298        cx: &mut Context<Self>,
15299    ) {
15300        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15301
15302        let buffer = self.buffer.read(cx).snapshot(cx);
15303        let selections = self
15304            .selections
15305            .all::<usize>(&self.display_snapshot(cx))
15306            .into_iter()
15307            // subtracting the offset requires sorting
15308            .sorted_by_key(|i| i.start);
15309
15310        let full_edits = selections
15311            .into_iter()
15312            .filter_map(|selection| {
15313                let child = if selection.is_empty()
15314                    && let Some((_, ancestor_range)) =
15315                        buffer.syntax_ancestor(selection.start..selection.end)
15316                {
15317                    ancestor_range
15318                } else {
15319                    selection.range()
15320                };
15321
15322                let mut parent = child.clone();
15323                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15324                    parent = ancestor_range;
15325                    if parent.start < child.start || parent.end > child.end {
15326                        break;
15327                    }
15328                }
15329
15330                if parent == child {
15331                    return None;
15332                }
15333                let text = buffer.text_for_range(child).collect::<String>();
15334                Some((selection.id, parent, text))
15335            })
15336            .collect::<Vec<_>>();
15337        if full_edits.is_empty() {
15338            return;
15339        }
15340
15341        self.transact(window, cx, |this, window, cx| {
15342            this.buffer.update(cx, |buffer, cx| {
15343                buffer.edit(
15344                    full_edits
15345                        .iter()
15346                        .map(|(_, p, t)| (p.clone(), t.clone()))
15347                        .collect::<Vec<_>>(),
15348                    None,
15349                    cx,
15350                );
15351            });
15352            this.change_selections(Default::default(), window, cx, |s| {
15353                let mut offset = 0;
15354                let mut selections = vec![];
15355                for (id, parent, text) in full_edits {
15356                    let start = parent.start - offset;
15357                    offset += parent.len() - text.len();
15358                    selections.push(Selection {
15359                        id,
15360                        start,
15361                        end: start + text.len(),
15362                        reversed: false,
15363                        goal: Default::default(),
15364                    });
15365                }
15366                s.select(selections);
15367            });
15368        });
15369    }
15370
15371    pub fn select_next_syntax_node(
15372        &mut self,
15373        _: &SelectNextSyntaxNode,
15374        window: &mut Window,
15375        cx: &mut Context<Self>,
15376    ) {
15377        let old_selections: Box<[_]> = self
15378            .selections
15379            .all::<usize>(&self.display_snapshot(cx))
15380            .into();
15381        if old_selections.is_empty() {
15382            return;
15383        }
15384
15385        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15386
15387        let buffer = self.buffer.read(cx).snapshot(cx);
15388        let mut selected_sibling = false;
15389
15390        let new_selections = old_selections
15391            .iter()
15392            .map(|selection| {
15393                let old_range = selection.start..selection.end;
15394
15395                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15396                    let new_range = node.byte_range();
15397                    selected_sibling = true;
15398                    Selection {
15399                        id: selection.id,
15400                        start: new_range.start,
15401                        end: new_range.end,
15402                        goal: SelectionGoal::None,
15403                        reversed: selection.reversed,
15404                    }
15405                } else {
15406                    selection.clone()
15407                }
15408            })
15409            .collect::<Vec<_>>();
15410
15411        if selected_sibling {
15412            self.change_selections(
15413                SelectionEffects::scroll(Autoscroll::fit()),
15414                window,
15415                cx,
15416                |s| {
15417                    s.select(new_selections);
15418                },
15419            );
15420        }
15421    }
15422
15423    pub fn select_prev_syntax_node(
15424        &mut self,
15425        _: &SelectPreviousSyntaxNode,
15426        window: &mut Window,
15427        cx: &mut Context<Self>,
15428    ) {
15429        let old_selections: Box<[_]> = self
15430            .selections
15431            .all::<usize>(&self.display_snapshot(cx))
15432            .into();
15433        if old_selections.is_empty() {
15434            return;
15435        }
15436
15437        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15438
15439        let buffer = self.buffer.read(cx).snapshot(cx);
15440        let mut selected_sibling = false;
15441
15442        let new_selections = old_selections
15443            .iter()
15444            .map(|selection| {
15445                let old_range = selection.start..selection.end;
15446
15447                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15448                    let new_range = node.byte_range();
15449                    selected_sibling = true;
15450                    Selection {
15451                        id: selection.id,
15452                        start: new_range.start,
15453                        end: new_range.end,
15454                        goal: SelectionGoal::None,
15455                        reversed: selection.reversed,
15456                    }
15457                } else {
15458                    selection.clone()
15459                }
15460            })
15461            .collect::<Vec<_>>();
15462
15463        if selected_sibling {
15464            self.change_selections(
15465                SelectionEffects::scroll(Autoscroll::fit()),
15466                window,
15467                cx,
15468                |s| {
15469                    s.select(new_selections);
15470                },
15471            );
15472        }
15473    }
15474
15475    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15476        if !EditorSettings::get_global(cx).gutter.runnables {
15477            self.clear_tasks();
15478            return Task::ready(());
15479        }
15480        let project = self.project().map(Entity::downgrade);
15481        let task_sources = self.lsp_task_sources(cx);
15482        let multi_buffer = self.buffer.downgrade();
15483        cx.spawn_in(window, async move |editor, cx| {
15484            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15485            let Some(project) = project.and_then(|p| p.upgrade()) else {
15486                return;
15487            };
15488            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15489                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15490            }) else {
15491                return;
15492            };
15493
15494            let hide_runnables = project
15495                .update(cx, |project, _| project.is_via_collab())
15496                .unwrap_or(true);
15497            if hide_runnables {
15498                return;
15499            }
15500            let new_rows =
15501                cx.background_spawn({
15502                    let snapshot = display_snapshot.clone();
15503                    async move {
15504                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15505                    }
15506                })
15507                    .await;
15508            let Ok(lsp_tasks) =
15509                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15510            else {
15511                return;
15512            };
15513            let lsp_tasks = lsp_tasks.await;
15514
15515            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15516                lsp_tasks
15517                    .into_iter()
15518                    .flat_map(|(kind, tasks)| {
15519                        tasks.into_iter().filter_map(move |(location, task)| {
15520                            Some((kind.clone(), location?, task))
15521                        })
15522                    })
15523                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15524                        let buffer = location.target.buffer;
15525                        let buffer_snapshot = buffer.read(cx).snapshot();
15526                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15527                            |(excerpt_id, snapshot, _)| {
15528                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15529                                    display_snapshot
15530                                        .buffer_snapshot()
15531                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15532                                } else {
15533                                    None
15534                                }
15535                            },
15536                        );
15537                        if let Some(offset) = offset {
15538                            let task_buffer_range =
15539                                location.target.range.to_point(&buffer_snapshot);
15540                            let context_buffer_range =
15541                                task_buffer_range.to_offset(&buffer_snapshot);
15542                            let context_range = BufferOffset(context_buffer_range.start)
15543                                ..BufferOffset(context_buffer_range.end);
15544
15545                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15546                                .or_insert_with(|| RunnableTasks {
15547                                    templates: Vec::new(),
15548                                    offset,
15549                                    column: task_buffer_range.start.column,
15550                                    extra_variables: HashMap::default(),
15551                                    context_range,
15552                                })
15553                                .templates
15554                                .push((kind, task.original_task().clone()));
15555                        }
15556
15557                        acc
15558                    })
15559            }) else {
15560                return;
15561            };
15562
15563            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15564                buffer.language_settings(cx).tasks.prefer_lsp
15565            }) else {
15566                return;
15567            };
15568
15569            let rows = Self::runnable_rows(
15570                project,
15571                display_snapshot,
15572                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15573                new_rows,
15574                cx.clone(),
15575            )
15576            .await;
15577            editor
15578                .update(cx, |editor, _| {
15579                    editor.clear_tasks();
15580                    for (key, mut value) in rows {
15581                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15582                            value.templates.extend(lsp_tasks.templates);
15583                        }
15584
15585                        editor.insert_tasks(key, value);
15586                    }
15587                    for (key, value) in lsp_tasks_by_rows {
15588                        editor.insert_tasks(key, value);
15589                    }
15590                })
15591                .ok();
15592        })
15593    }
15594    fn fetch_runnable_ranges(
15595        snapshot: &DisplaySnapshot,
15596        range: Range<Anchor>,
15597    ) -> Vec<language::RunnableRange> {
15598        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15599    }
15600
15601    fn runnable_rows(
15602        project: Entity<Project>,
15603        snapshot: DisplaySnapshot,
15604        prefer_lsp: bool,
15605        runnable_ranges: Vec<RunnableRange>,
15606        cx: AsyncWindowContext,
15607    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15608        cx.spawn(async move |cx| {
15609            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15610            for mut runnable in runnable_ranges {
15611                let Some(tasks) = cx
15612                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15613                    .ok()
15614                else {
15615                    continue;
15616                };
15617                let mut tasks = tasks.await;
15618
15619                if prefer_lsp {
15620                    tasks.retain(|(task_kind, _)| {
15621                        !matches!(task_kind, TaskSourceKind::Language { .. })
15622                    });
15623                }
15624                if tasks.is_empty() {
15625                    continue;
15626                }
15627
15628                let point = runnable
15629                    .run_range
15630                    .start
15631                    .to_point(&snapshot.buffer_snapshot());
15632                let Some(row) = snapshot
15633                    .buffer_snapshot()
15634                    .buffer_line_for_row(MultiBufferRow(point.row))
15635                    .map(|(_, range)| range.start.row)
15636                else {
15637                    continue;
15638                };
15639
15640                let context_range =
15641                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15642                runnable_rows.push((
15643                    (runnable.buffer_id, row),
15644                    RunnableTasks {
15645                        templates: tasks,
15646                        offset: snapshot
15647                            .buffer_snapshot()
15648                            .anchor_before(runnable.run_range.start),
15649                        context_range,
15650                        column: point.column,
15651                        extra_variables: runnable.extra_captures,
15652                    },
15653                ));
15654            }
15655            runnable_rows
15656        })
15657    }
15658
15659    fn templates_with_tags(
15660        project: &Entity<Project>,
15661        runnable: &mut Runnable,
15662        cx: &mut App,
15663    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15664        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15665            let (worktree_id, file) = project
15666                .buffer_for_id(runnable.buffer, cx)
15667                .and_then(|buffer| buffer.read(cx).file())
15668                .map(|file| (file.worktree_id(cx), file.clone()))
15669                .unzip();
15670
15671            (
15672                project.task_store().read(cx).task_inventory().cloned(),
15673                worktree_id,
15674                file,
15675            )
15676        });
15677
15678        let tags = mem::take(&mut runnable.tags);
15679        let language = runnable.language.clone();
15680        cx.spawn(async move |cx| {
15681            let mut templates_with_tags = Vec::new();
15682            if let Some(inventory) = inventory {
15683                for RunnableTag(tag) in tags {
15684                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15685                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15686                    }) else {
15687                        return templates_with_tags;
15688                    };
15689                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15690                        move |(_, template)| {
15691                            template.tags.iter().any(|source_tag| source_tag == &tag)
15692                        },
15693                    ));
15694                }
15695            }
15696            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15697
15698            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15699                // Strongest source wins; if we have worktree tag binding, prefer that to
15700                // global and language bindings;
15701                // if we have a global binding, prefer that to language binding.
15702                let first_mismatch = templates_with_tags
15703                    .iter()
15704                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15705                if let Some(index) = first_mismatch {
15706                    templates_with_tags.truncate(index);
15707                }
15708            }
15709
15710            templates_with_tags
15711        })
15712    }
15713
15714    pub fn move_to_enclosing_bracket(
15715        &mut self,
15716        _: &MoveToEnclosingBracket,
15717        window: &mut Window,
15718        cx: &mut Context<Self>,
15719    ) {
15720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15721        self.change_selections(Default::default(), window, cx, |s| {
15722            s.move_offsets_with(|snapshot, selection| {
15723                let Some(enclosing_bracket_ranges) =
15724                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15725                else {
15726                    return;
15727                };
15728
15729                let mut best_length = usize::MAX;
15730                let mut best_inside = false;
15731                let mut best_in_bracket_range = false;
15732                let mut best_destination = None;
15733                for (open, close) in enclosing_bracket_ranges {
15734                    let close = close.to_inclusive();
15735                    let length = close.end() - open.start;
15736                    let inside = selection.start >= open.end && selection.end <= *close.start();
15737                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15738                        || close.contains(&selection.head());
15739
15740                    // If best is next to a bracket and current isn't, skip
15741                    if !in_bracket_range && best_in_bracket_range {
15742                        continue;
15743                    }
15744
15745                    // Prefer smaller lengths unless best is inside and current isn't
15746                    if length > best_length && (best_inside || !inside) {
15747                        continue;
15748                    }
15749
15750                    best_length = length;
15751                    best_inside = inside;
15752                    best_in_bracket_range = in_bracket_range;
15753                    best_destination = Some(
15754                        if close.contains(&selection.start) && close.contains(&selection.end) {
15755                            if inside { open.end } else { open.start }
15756                        } else if inside {
15757                            *close.start()
15758                        } else {
15759                            *close.end()
15760                        },
15761                    );
15762                }
15763
15764                if let Some(destination) = best_destination {
15765                    selection.collapse_to(destination, SelectionGoal::None);
15766                }
15767            })
15768        });
15769    }
15770
15771    pub fn undo_selection(
15772        &mut self,
15773        _: &UndoSelection,
15774        window: &mut Window,
15775        cx: &mut Context<Self>,
15776    ) {
15777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15778        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15779            self.selection_history.mode = SelectionHistoryMode::Undoing;
15780            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15781                this.end_selection(window, cx);
15782                this.change_selections(
15783                    SelectionEffects::scroll(Autoscroll::newest()),
15784                    window,
15785                    cx,
15786                    |s| s.select_anchors(entry.selections.to_vec()),
15787                );
15788            });
15789            self.selection_history.mode = SelectionHistoryMode::Normal;
15790
15791            self.select_next_state = entry.select_next_state;
15792            self.select_prev_state = entry.select_prev_state;
15793            self.add_selections_state = entry.add_selections_state;
15794        }
15795    }
15796
15797    pub fn redo_selection(
15798        &mut self,
15799        _: &RedoSelection,
15800        window: &mut Window,
15801        cx: &mut Context<Self>,
15802    ) {
15803        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15804        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15805            self.selection_history.mode = SelectionHistoryMode::Redoing;
15806            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15807                this.end_selection(window, cx);
15808                this.change_selections(
15809                    SelectionEffects::scroll(Autoscroll::newest()),
15810                    window,
15811                    cx,
15812                    |s| s.select_anchors(entry.selections.to_vec()),
15813                );
15814            });
15815            self.selection_history.mode = SelectionHistoryMode::Normal;
15816
15817            self.select_next_state = entry.select_next_state;
15818            self.select_prev_state = entry.select_prev_state;
15819            self.add_selections_state = entry.add_selections_state;
15820        }
15821    }
15822
15823    pub fn expand_excerpts(
15824        &mut self,
15825        action: &ExpandExcerpts,
15826        _: &mut Window,
15827        cx: &mut Context<Self>,
15828    ) {
15829        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15830    }
15831
15832    pub fn expand_excerpts_down(
15833        &mut self,
15834        action: &ExpandExcerptsDown,
15835        _: &mut Window,
15836        cx: &mut Context<Self>,
15837    ) {
15838        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15839    }
15840
15841    pub fn expand_excerpts_up(
15842        &mut self,
15843        action: &ExpandExcerptsUp,
15844        _: &mut Window,
15845        cx: &mut Context<Self>,
15846    ) {
15847        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15848    }
15849
15850    pub fn expand_excerpts_for_direction(
15851        &mut self,
15852        lines: u32,
15853        direction: ExpandExcerptDirection,
15854
15855        cx: &mut Context<Self>,
15856    ) {
15857        let selections = self.selections.disjoint_anchors_arc();
15858
15859        let lines = if lines == 0 {
15860            EditorSettings::get_global(cx).expand_excerpt_lines
15861        } else {
15862            lines
15863        };
15864
15865        self.buffer.update(cx, |buffer, cx| {
15866            let snapshot = buffer.snapshot(cx);
15867            let mut excerpt_ids = selections
15868                .iter()
15869                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15870                .collect::<Vec<_>>();
15871            excerpt_ids.sort();
15872            excerpt_ids.dedup();
15873            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15874        })
15875    }
15876
15877    pub fn expand_excerpt(
15878        &mut self,
15879        excerpt: ExcerptId,
15880        direction: ExpandExcerptDirection,
15881        window: &mut Window,
15882        cx: &mut Context<Self>,
15883    ) {
15884        let current_scroll_position = self.scroll_position(cx);
15885        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15886        let mut scroll = None;
15887
15888        if direction == ExpandExcerptDirection::Down {
15889            let multi_buffer = self.buffer.read(cx);
15890            let snapshot = multi_buffer.snapshot(cx);
15891            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15892                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15893                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15894            {
15895                let buffer_snapshot = buffer.read(cx).snapshot();
15896                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15897                let last_row = buffer_snapshot.max_point().row;
15898                let lines_below = last_row.saturating_sub(excerpt_end_row);
15899                if lines_below >= lines_to_expand {
15900                    scroll = Some(
15901                        current_scroll_position
15902                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
15903                    );
15904                }
15905            }
15906        }
15907        if direction == ExpandExcerptDirection::Up
15908            && self
15909                .buffer
15910                .read(cx)
15911                .snapshot(cx)
15912                .excerpt_before(excerpt)
15913                .is_none()
15914        {
15915            scroll = Some(current_scroll_position);
15916        }
15917
15918        self.buffer.update(cx, |buffer, cx| {
15919            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15920        });
15921
15922        if let Some(new_scroll_position) = scroll {
15923            self.set_scroll_position(new_scroll_position, window, cx);
15924        }
15925    }
15926
15927    pub fn go_to_singleton_buffer_point(
15928        &mut self,
15929        point: Point,
15930        window: &mut Window,
15931        cx: &mut Context<Self>,
15932    ) {
15933        self.go_to_singleton_buffer_range(point..point, window, cx);
15934    }
15935
15936    pub fn go_to_singleton_buffer_range(
15937        &mut self,
15938        range: Range<Point>,
15939        window: &mut Window,
15940        cx: &mut Context<Self>,
15941    ) {
15942        let multibuffer = self.buffer().read(cx);
15943        let Some(buffer) = multibuffer.as_singleton() else {
15944            return;
15945        };
15946        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15947            return;
15948        };
15949        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15950            return;
15951        };
15952        self.change_selections(
15953            SelectionEffects::default().nav_history(true),
15954            window,
15955            cx,
15956            |s| s.select_anchor_ranges([start..end]),
15957        );
15958    }
15959
15960    pub fn go_to_diagnostic(
15961        &mut self,
15962        action: &GoToDiagnostic,
15963        window: &mut Window,
15964        cx: &mut Context<Self>,
15965    ) {
15966        if !self.diagnostics_enabled() {
15967            return;
15968        }
15969        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15970        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15971    }
15972
15973    pub fn go_to_prev_diagnostic(
15974        &mut self,
15975        action: &GoToPreviousDiagnostic,
15976        window: &mut Window,
15977        cx: &mut Context<Self>,
15978    ) {
15979        if !self.diagnostics_enabled() {
15980            return;
15981        }
15982        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15983        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15984    }
15985
15986    pub fn go_to_diagnostic_impl(
15987        &mut self,
15988        direction: Direction,
15989        severity: GoToDiagnosticSeverityFilter,
15990        window: &mut Window,
15991        cx: &mut Context<Self>,
15992    ) {
15993        let buffer = self.buffer.read(cx).snapshot(cx);
15994        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
15995
15996        let mut active_group_id = None;
15997        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15998            && active_group.active_range.start.to_offset(&buffer) == selection.start
15999        {
16000            active_group_id = Some(active_group.group_id);
16001        }
16002
16003        fn filtered<'a>(
16004            snapshot: EditorSnapshot,
16005            severity: GoToDiagnosticSeverityFilter,
16006            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16007        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16008            diagnostics
16009                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16010                .filter(|entry| entry.range.start != entry.range.end)
16011                .filter(|entry| !entry.diagnostic.is_unnecessary)
16012                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16013        }
16014
16015        let snapshot = self.snapshot(window, cx);
16016        let before = filtered(
16017            snapshot.clone(),
16018            severity,
16019            buffer
16020                .diagnostics_in_range(0..selection.start)
16021                .filter(|entry| entry.range.start <= selection.start),
16022        );
16023        let after = filtered(
16024            snapshot,
16025            severity,
16026            buffer
16027                .diagnostics_in_range(selection.start..buffer.len())
16028                .filter(|entry| entry.range.start >= selection.start),
16029        );
16030
16031        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16032        if direction == Direction::Prev {
16033            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16034            {
16035                for diagnostic in prev_diagnostics.into_iter().rev() {
16036                    if diagnostic.range.start != selection.start
16037                        || active_group_id
16038                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16039                    {
16040                        found = Some(diagnostic);
16041                        break 'outer;
16042                    }
16043                }
16044            }
16045        } else {
16046            for diagnostic in after.chain(before) {
16047                if diagnostic.range.start != selection.start
16048                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16049                {
16050                    found = Some(diagnostic);
16051                    break;
16052                }
16053            }
16054        }
16055        let Some(next_diagnostic) = found else {
16056            return;
16057        };
16058
16059        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16060        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16061            return;
16062        };
16063        self.change_selections(Default::default(), window, cx, |s| {
16064            s.select_ranges(vec![
16065                next_diagnostic.range.start..next_diagnostic.range.start,
16066            ])
16067        });
16068        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16069        self.refresh_edit_prediction(false, true, window, cx);
16070    }
16071
16072    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16073        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16074        let snapshot = self.snapshot(window, cx);
16075        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16076        self.go_to_hunk_before_or_after_position(
16077            &snapshot,
16078            selection.head(),
16079            Direction::Next,
16080            window,
16081            cx,
16082        );
16083    }
16084
16085    pub fn go_to_hunk_before_or_after_position(
16086        &mut self,
16087        snapshot: &EditorSnapshot,
16088        position: Point,
16089        direction: Direction,
16090        window: &mut Window,
16091        cx: &mut Context<Editor>,
16092    ) {
16093        let row = if direction == Direction::Next {
16094            self.hunk_after_position(snapshot, position)
16095                .map(|hunk| hunk.row_range.start)
16096        } else {
16097            self.hunk_before_position(snapshot, position)
16098        };
16099
16100        if let Some(row) = row {
16101            let destination = Point::new(row.0, 0);
16102            let autoscroll = Autoscroll::center();
16103
16104            self.unfold_ranges(&[destination..destination], false, false, cx);
16105            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16106                s.select_ranges([destination..destination]);
16107            });
16108        }
16109    }
16110
16111    fn hunk_after_position(
16112        &mut self,
16113        snapshot: &EditorSnapshot,
16114        position: Point,
16115    ) -> Option<MultiBufferDiffHunk> {
16116        snapshot
16117            .buffer_snapshot()
16118            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16119            .find(|hunk| hunk.row_range.start.0 > position.row)
16120            .or_else(|| {
16121                snapshot
16122                    .buffer_snapshot()
16123                    .diff_hunks_in_range(Point::zero()..position)
16124                    .find(|hunk| hunk.row_range.end.0 < position.row)
16125            })
16126    }
16127
16128    fn go_to_prev_hunk(
16129        &mut self,
16130        _: &GoToPreviousHunk,
16131        window: &mut Window,
16132        cx: &mut Context<Self>,
16133    ) {
16134        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16135        let snapshot = self.snapshot(window, cx);
16136        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16137        self.go_to_hunk_before_or_after_position(
16138            &snapshot,
16139            selection.head(),
16140            Direction::Prev,
16141            window,
16142            cx,
16143        );
16144    }
16145
16146    fn hunk_before_position(
16147        &mut self,
16148        snapshot: &EditorSnapshot,
16149        position: Point,
16150    ) -> Option<MultiBufferRow> {
16151        snapshot
16152            .buffer_snapshot()
16153            .diff_hunk_before(position)
16154            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16155    }
16156
16157    fn go_to_next_change(
16158        &mut self,
16159        _: &GoToNextChange,
16160        window: &mut Window,
16161        cx: &mut Context<Self>,
16162    ) {
16163        if let Some(selections) = self
16164            .change_list
16165            .next_change(1, Direction::Next)
16166            .map(|s| s.to_vec())
16167        {
16168            self.change_selections(Default::default(), window, cx, |s| {
16169                let map = s.display_map();
16170                s.select_display_ranges(selections.iter().map(|a| {
16171                    let point = a.to_display_point(&map);
16172                    point..point
16173                }))
16174            })
16175        }
16176    }
16177
16178    fn go_to_previous_change(
16179        &mut self,
16180        _: &GoToPreviousChange,
16181        window: &mut Window,
16182        cx: &mut Context<Self>,
16183    ) {
16184        if let Some(selections) = self
16185            .change_list
16186            .next_change(1, Direction::Prev)
16187            .map(|s| s.to_vec())
16188        {
16189            self.change_selections(Default::default(), window, cx, |s| {
16190                let map = s.display_map();
16191                s.select_display_ranges(selections.iter().map(|a| {
16192                    let point = a.to_display_point(&map);
16193                    point..point
16194                }))
16195            })
16196        }
16197    }
16198
16199    pub fn go_to_next_document_highlight(
16200        &mut self,
16201        _: &GoToNextDocumentHighlight,
16202        window: &mut Window,
16203        cx: &mut Context<Self>,
16204    ) {
16205        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16206    }
16207
16208    pub fn go_to_prev_document_highlight(
16209        &mut self,
16210        _: &GoToPreviousDocumentHighlight,
16211        window: &mut Window,
16212        cx: &mut Context<Self>,
16213    ) {
16214        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16215    }
16216
16217    pub fn go_to_document_highlight_before_or_after_position(
16218        &mut self,
16219        direction: Direction,
16220        window: &mut Window,
16221        cx: &mut Context<Editor>,
16222    ) {
16223        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16224        let snapshot = self.snapshot(window, cx);
16225        let buffer = &snapshot.buffer_snapshot();
16226        let position = self
16227            .selections
16228            .newest::<Point>(&snapshot.display_snapshot)
16229            .head();
16230        let anchor_position = buffer.anchor_after(position);
16231
16232        // Get all document highlights (both read and write)
16233        let mut all_highlights = Vec::new();
16234
16235        if let Some((_, read_highlights)) = self
16236            .background_highlights
16237            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16238        {
16239            all_highlights.extend(read_highlights.iter());
16240        }
16241
16242        if let Some((_, write_highlights)) = self
16243            .background_highlights
16244            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16245        {
16246            all_highlights.extend(write_highlights.iter());
16247        }
16248
16249        if all_highlights.is_empty() {
16250            return;
16251        }
16252
16253        // Sort highlights by position
16254        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16255
16256        let target_highlight = match direction {
16257            Direction::Next => {
16258                // Find the first highlight after the current position
16259                all_highlights
16260                    .iter()
16261                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16262            }
16263            Direction::Prev => {
16264                // Find the last highlight before the current position
16265                all_highlights
16266                    .iter()
16267                    .rev()
16268                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16269            }
16270        };
16271
16272        if let Some(highlight) = target_highlight {
16273            let destination = highlight.start.to_point(buffer);
16274            let autoscroll = Autoscroll::center();
16275
16276            self.unfold_ranges(&[destination..destination], false, false, cx);
16277            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16278                s.select_ranges([destination..destination]);
16279            });
16280        }
16281    }
16282
16283    fn go_to_line<T: 'static>(
16284        &mut self,
16285        position: Anchor,
16286        highlight_color: Option<Hsla>,
16287        window: &mut Window,
16288        cx: &mut Context<Self>,
16289    ) {
16290        let snapshot = self.snapshot(window, cx).display_snapshot;
16291        let position = position.to_point(&snapshot.buffer_snapshot());
16292        let start = snapshot
16293            .buffer_snapshot()
16294            .clip_point(Point::new(position.row, 0), Bias::Left);
16295        let end = start + Point::new(1, 0);
16296        let start = snapshot.buffer_snapshot().anchor_before(start);
16297        let end = snapshot.buffer_snapshot().anchor_before(end);
16298
16299        self.highlight_rows::<T>(
16300            start..end,
16301            highlight_color
16302                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16303            Default::default(),
16304            cx,
16305        );
16306
16307        if self.buffer.read(cx).is_singleton() {
16308            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16309        }
16310    }
16311
16312    pub fn go_to_definition(
16313        &mut self,
16314        _: &GoToDefinition,
16315        window: &mut Window,
16316        cx: &mut Context<Self>,
16317    ) -> Task<Result<Navigated>> {
16318        let definition =
16319            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16320        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16321        cx.spawn_in(window, async move |editor, cx| {
16322            if definition.await? == Navigated::Yes {
16323                return Ok(Navigated::Yes);
16324            }
16325            match fallback_strategy {
16326                GoToDefinitionFallback::None => Ok(Navigated::No),
16327                GoToDefinitionFallback::FindAllReferences => {
16328                    match editor.update_in(cx, |editor, window, cx| {
16329                        editor.find_all_references(&FindAllReferences, window, cx)
16330                    })? {
16331                        Some(references) => references.await,
16332                        None => Ok(Navigated::No),
16333                    }
16334                }
16335            }
16336        })
16337    }
16338
16339    pub fn go_to_declaration(
16340        &mut self,
16341        _: &GoToDeclaration,
16342        window: &mut Window,
16343        cx: &mut Context<Self>,
16344    ) -> Task<Result<Navigated>> {
16345        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16346    }
16347
16348    pub fn go_to_declaration_split(
16349        &mut self,
16350        _: &GoToDeclaration,
16351        window: &mut Window,
16352        cx: &mut Context<Self>,
16353    ) -> Task<Result<Navigated>> {
16354        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16355    }
16356
16357    pub fn go_to_implementation(
16358        &mut self,
16359        _: &GoToImplementation,
16360        window: &mut Window,
16361        cx: &mut Context<Self>,
16362    ) -> Task<Result<Navigated>> {
16363        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16364    }
16365
16366    pub fn go_to_implementation_split(
16367        &mut self,
16368        _: &GoToImplementationSplit,
16369        window: &mut Window,
16370        cx: &mut Context<Self>,
16371    ) -> Task<Result<Navigated>> {
16372        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16373    }
16374
16375    pub fn go_to_type_definition(
16376        &mut self,
16377        _: &GoToTypeDefinition,
16378        window: &mut Window,
16379        cx: &mut Context<Self>,
16380    ) -> Task<Result<Navigated>> {
16381        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16382    }
16383
16384    pub fn go_to_definition_split(
16385        &mut self,
16386        _: &GoToDefinitionSplit,
16387        window: &mut Window,
16388        cx: &mut Context<Self>,
16389    ) -> Task<Result<Navigated>> {
16390        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16391    }
16392
16393    pub fn go_to_type_definition_split(
16394        &mut self,
16395        _: &GoToTypeDefinitionSplit,
16396        window: &mut Window,
16397        cx: &mut Context<Self>,
16398    ) -> Task<Result<Navigated>> {
16399        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16400    }
16401
16402    fn go_to_definition_of_kind(
16403        &mut self,
16404        kind: GotoDefinitionKind,
16405        split: bool,
16406        window: &mut Window,
16407        cx: &mut Context<Self>,
16408    ) -> Task<Result<Navigated>> {
16409        let Some(provider) = self.semantics_provider.clone() else {
16410            return Task::ready(Ok(Navigated::No));
16411        };
16412        let head = self
16413            .selections
16414            .newest::<usize>(&self.display_snapshot(cx))
16415            .head();
16416        let buffer = self.buffer.read(cx);
16417        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16418            return Task::ready(Ok(Navigated::No));
16419        };
16420        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16421            return Task::ready(Ok(Navigated::No));
16422        };
16423
16424        cx.spawn_in(window, async move |editor, cx| {
16425            let Some(definitions) = definitions.await? else {
16426                return Ok(Navigated::No);
16427            };
16428            let navigated = editor
16429                .update_in(cx, |editor, window, cx| {
16430                    editor.navigate_to_hover_links(
16431                        Some(kind),
16432                        definitions
16433                            .into_iter()
16434                            .filter(|location| {
16435                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16436                            })
16437                            .map(HoverLink::Text)
16438                            .collect::<Vec<_>>(),
16439                        split,
16440                        window,
16441                        cx,
16442                    )
16443                })?
16444                .await?;
16445            anyhow::Ok(navigated)
16446        })
16447    }
16448
16449    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16450        let selection = self.selections.newest_anchor();
16451        let head = selection.head();
16452        let tail = selection.tail();
16453
16454        let Some((buffer, start_position)) =
16455            self.buffer.read(cx).text_anchor_for_position(head, cx)
16456        else {
16457            return;
16458        };
16459
16460        let end_position = if head != tail {
16461            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16462                return;
16463            };
16464            Some(pos)
16465        } else {
16466            None
16467        };
16468
16469        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16470            let url = if let Some(end_pos) = end_position {
16471                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16472            } else {
16473                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16474            };
16475
16476            if let Some(url) = url {
16477                cx.update(|window, cx| {
16478                    if parse_zed_link(&url, cx).is_some() {
16479                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16480                    } else {
16481                        cx.open_url(&url);
16482                    }
16483                })?;
16484            }
16485
16486            anyhow::Ok(())
16487        });
16488
16489        url_finder.detach();
16490    }
16491
16492    pub fn open_selected_filename(
16493        &mut self,
16494        _: &OpenSelectedFilename,
16495        window: &mut Window,
16496        cx: &mut Context<Self>,
16497    ) {
16498        let Some(workspace) = self.workspace() else {
16499            return;
16500        };
16501
16502        let position = self.selections.newest_anchor().head();
16503
16504        let Some((buffer, buffer_position)) =
16505            self.buffer.read(cx).text_anchor_for_position(position, cx)
16506        else {
16507            return;
16508        };
16509
16510        let project = self.project.clone();
16511
16512        cx.spawn_in(window, async move |_, cx| {
16513            let result = find_file(&buffer, project, buffer_position, cx).await;
16514
16515            if let Some((_, path)) = result {
16516                workspace
16517                    .update_in(cx, |workspace, window, cx| {
16518                        workspace.open_resolved_path(path, window, cx)
16519                    })?
16520                    .await?;
16521            }
16522            anyhow::Ok(())
16523        })
16524        .detach();
16525    }
16526
16527    pub(crate) fn navigate_to_hover_links(
16528        &mut self,
16529        kind: Option<GotoDefinitionKind>,
16530        definitions: Vec<HoverLink>,
16531        split: bool,
16532        window: &mut Window,
16533        cx: &mut Context<Editor>,
16534    ) -> Task<Result<Navigated>> {
16535        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16536        let mut first_url_or_file = None;
16537        let definitions: Vec<_> = definitions
16538            .into_iter()
16539            .filter_map(|def| match def {
16540                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16541                HoverLink::InlayHint(lsp_location, server_id) => {
16542                    let computation =
16543                        self.compute_target_location(lsp_location, server_id, window, cx);
16544                    Some(cx.background_spawn(computation))
16545                }
16546                HoverLink::Url(url) => {
16547                    first_url_or_file = Some(Either::Left(url));
16548                    None
16549                }
16550                HoverLink::File(path) => {
16551                    first_url_or_file = Some(Either::Right(path));
16552                    None
16553                }
16554            })
16555            .collect();
16556
16557        let workspace = self.workspace();
16558
16559        cx.spawn_in(window, async move |editor, cx| {
16560            let locations: Vec<Location> = future::join_all(definitions)
16561                .await
16562                .into_iter()
16563                .filter_map(|location| location.transpose())
16564                .collect::<Result<_>>()
16565                .context("location tasks")?;
16566            let mut locations = cx.update(|_, cx| {
16567                locations
16568                    .into_iter()
16569                    .map(|location| {
16570                        let buffer = location.buffer.read(cx);
16571                        (location.buffer, location.range.to_point(buffer))
16572                    })
16573                    .into_group_map()
16574            })?;
16575            let mut num_locations = 0;
16576            for ranges in locations.values_mut() {
16577                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16578                ranges.dedup();
16579                num_locations += ranges.len();
16580            }
16581
16582            if num_locations > 1 {
16583                let Some(workspace) = workspace else {
16584                    return Ok(Navigated::No);
16585                };
16586
16587                let tab_kind = match kind {
16588                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16589                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16590                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16591                    Some(GotoDefinitionKind::Type) => "Types",
16592                };
16593                let title = editor
16594                    .update_in(cx, |_, _, cx| {
16595                        let target = locations
16596                            .iter()
16597                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16598                            .map(|(buffer, location)| {
16599                                buffer
16600                                    .read(cx)
16601                                    .text_for_range(location.clone())
16602                                    .collect::<String>()
16603                            })
16604                            .filter(|text| !text.contains('\n'))
16605                            .unique()
16606                            .take(3)
16607                            .join(", ");
16608                        if target.is_empty() {
16609                            tab_kind.to_owned()
16610                        } else {
16611                            format!("{tab_kind} for {target}")
16612                        }
16613                    })
16614                    .context("buffer title")?;
16615
16616                let opened = workspace
16617                    .update_in(cx, |workspace, window, cx| {
16618                        Self::open_locations_in_multibuffer(
16619                            workspace,
16620                            locations,
16621                            title,
16622                            split,
16623                            MultibufferSelectionMode::First,
16624                            window,
16625                            cx,
16626                        )
16627                    })
16628                    .is_ok();
16629
16630                anyhow::Ok(Navigated::from_bool(opened))
16631            } else if num_locations == 0 {
16632                // If there is one url or file, open it directly
16633                match first_url_or_file {
16634                    Some(Either::Left(url)) => {
16635                        cx.update(|_, cx| cx.open_url(&url))?;
16636                        Ok(Navigated::Yes)
16637                    }
16638                    Some(Either::Right(path)) => {
16639                        let Some(workspace) = workspace else {
16640                            return Ok(Navigated::No);
16641                        };
16642
16643                        workspace
16644                            .update_in(cx, |workspace, window, cx| {
16645                                workspace.open_resolved_path(path, window, cx)
16646                            })?
16647                            .await?;
16648                        Ok(Navigated::Yes)
16649                    }
16650                    None => Ok(Navigated::No),
16651                }
16652            } else {
16653                let Some(workspace) = workspace else {
16654                    return Ok(Navigated::No);
16655                };
16656
16657                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16658                let target_range = target_ranges.first().unwrap().clone();
16659
16660                editor.update_in(cx, |editor, window, cx| {
16661                    let range = target_range.to_point(target_buffer.read(cx));
16662                    let range = editor.range_for_match(&range, false);
16663                    let range = collapse_multiline_range(range);
16664
16665                    if !split
16666                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16667                    {
16668                        editor.go_to_singleton_buffer_range(range, window, cx);
16669                    } else {
16670                        let pane = workspace.read(cx).active_pane().clone();
16671                        window.defer(cx, move |window, cx| {
16672                            let target_editor: Entity<Self> =
16673                                workspace.update(cx, |workspace, cx| {
16674                                    let pane = if split {
16675                                        workspace.adjacent_pane(window, cx)
16676                                    } else {
16677                                        workspace.active_pane().clone()
16678                                    };
16679
16680                                    workspace.open_project_item(
16681                                        pane,
16682                                        target_buffer.clone(),
16683                                        true,
16684                                        true,
16685                                        window,
16686                                        cx,
16687                                    )
16688                                });
16689                            target_editor.update(cx, |target_editor, cx| {
16690                                // When selecting a definition in a different buffer, disable the nav history
16691                                // to avoid creating a history entry at the previous cursor location.
16692                                pane.update(cx, |pane, _| pane.disable_history());
16693                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16694                                pane.update(cx, |pane, _| pane.enable_history());
16695                            });
16696                        });
16697                    }
16698                    Navigated::Yes
16699                })
16700            }
16701        })
16702    }
16703
16704    fn compute_target_location(
16705        &self,
16706        lsp_location: lsp::Location,
16707        server_id: LanguageServerId,
16708        window: &mut Window,
16709        cx: &mut Context<Self>,
16710    ) -> Task<anyhow::Result<Option<Location>>> {
16711        let Some(project) = self.project.clone() else {
16712            return Task::ready(Ok(None));
16713        };
16714
16715        cx.spawn_in(window, async move |editor, cx| {
16716            let location_task = editor.update(cx, |_, cx| {
16717                project.update(cx, |project, cx| {
16718                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16719                })
16720            })?;
16721            let location = Some({
16722                let target_buffer_handle = location_task.await.context("open local buffer")?;
16723                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16724                    let target_start = target_buffer
16725                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16726                    let target_end = target_buffer
16727                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16728                    target_buffer.anchor_after(target_start)
16729                        ..target_buffer.anchor_before(target_end)
16730                })?;
16731                Location {
16732                    buffer: target_buffer_handle,
16733                    range,
16734                }
16735            });
16736            Ok(location)
16737        })
16738    }
16739
16740    fn go_to_next_reference(
16741        &mut self,
16742        _: &GoToNextReference,
16743        window: &mut Window,
16744        cx: &mut Context<Self>,
16745    ) {
16746        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16747        if let Some(task) = task {
16748            task.detach();
16749        };
16750    }
16751
16752    fn go_to_prev_reference(
16753        &mut self,
16754        _: &GoToPreviousReference,
16755        window: &mut Window,
16756        cx: &mut Context<Self>,
16757    ) {
16758        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16759        if let Some(task) = task {
16760            task.detach();
16761        };
16762    }
16763
16764    pub fn go_to_reference_before_or_after_position(
16765        &mut self,
16766        direction: Direction,
16767        count: usize,
16768        window: &mut Window,
16769        cx: &mut Context<Self>,
16770    ) -> Option<Task<Result<()>>> {
16771        let selection = self.selections.newest_anchor();
16772        let head = selection.head();
16773
16774        let multi_buffer = self.buffer.read(cx);
16775
16776        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16777        let workspace = self.workspace()?;
16778        let project = workspace.read(cx).project().clone();
16779        let references =
16780            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16781        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16782            let Some(locations) = references.await? else {
16783                return Ok(());
16784            };
16785
16786            if locations.is_empty() {
16787                // totally normal - the cursor may be on something which is not
16788                // a symbol (e.g. a keyword)
16789                log::info!("no references found under cursor");
16790                return Ok(());
16791            }
16792
16793            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16794
16795            let multi_buffer_snapshot =
16796                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16797
16798            let (locations, current_location_index) =
16799                multi_buffer.update(cx, |multi_buffer, cx| {
16800                    let mut locations = locations
16801                        .into_iter()
16802                        .filter_map(|loc| {
16803                            let start = multi_buffer.buffer_anchor_to_anchor(
16804                                &loc.buffer,
16805                                loc.range.start,
16806                                cx,
16807                            )?;
16808                            let end = multi_buffer.buffer_anchor_to_anchor(
16809                                &loc.buffer,
16810                                loc.range.end,
16811                                cx,
16812                            )?;
16813                            Some(start..end)
16814                        })
16815                        .collect::<Vec<_>>();
16816
16817                    // There is an O(n) implementation, but given this list will be
16818                    // small (usually <100 items), the extra O(log(n)) factor isn't
16819                    // worth the (surprisingly large amount of) extra complexity.
16820                    locations
16821                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16822
16823                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16824
16825                    let current_location_index = locations.iter().position(|loc| {
16826                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16827                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16828                    });
16829
16830                    (locations, current_location_index)
16831                })?;
16832
16833            let Some(current_location_index) = current_location_index else {
16834                // This indicates something has gone wrong, because we already
16835                // handle the "no references" case above
16836                log::error!(
16837                    "failed to find current reference under cursor. Total references: {}",
16838                    locations.len()
16839                );
16840                return Ok(());
16841            };
16842
16843            let destination_location_index = match direction {
16844                Direction::Next => (current_location_index + count) % locations.len(),
16845                Direction::Prev => {
16846                    (current_location_index + locations.len() - count % locations.len())
16847                        % locations.len()
16848                }
16849            };
16850
16851            // TODO(cameron): is this needed?
16852            // the thinking is to avoid "jumping to the current location" (avoid
16853            // polluting "jumplist" in vim terms)
16854            if current_location_index == destination_location_index {
16855                return Ok(());
16856            }
16857
16858            let Range { start, end } = locations[destination_location_index];
16859
16860            editor.update_in(cx, |editor, window, cx| {
16861                let effects = SelectionEffects::default();
16862
16863                editor.unfold_ranges(&[start..end], false, false, cx);
16864                editor.change_selections(effects, window, cx, |s| {
16865                    s.select_ranges([start..start]);
16866                });
16867            })?;
16868
16869            Ok(())
16870        }))
16871    }
16872
16873    pub fn find_all_references(
16874        &mut self,
16875        _: &FindAllReferences,
16876        window: &mut Window,
16877        cx: &mut Context<Self>,
16878    ) -> Option<Task<Result<Navigated>>> {
16879        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16880        let multi_buffer = self.buffer.read(cx);
16881        let head = selection.head();
16882
16883        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16884        let head_anchor = multi_buffer_snapshot.anchor_at(
16885            head,
16886            if head < selection.tail() {
16887                Bias::Right
16888            } else {
16889                Bias::Left
16890            },
16891        );
16892
16893        match self
16894            .find_all_references_task_sources
16895            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16896        {
16897            Ok(_) => {
16898                log::info!(
16899                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16900                );
16901                return None;
16902            }
16903            Err(i) => {
16904                self.find_all_references_task_sources.insert(i, head_anchor);
16905            }
16906        }
16907
16908        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16909        let workspace = self.workspace()?;
16910        let project = workspace.read(cx).project().clone();
16911        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16912        Some(cx.spawn_in(window, async move |editor, cx| {
16913            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16914                if let Ok(i) = editor
16915                    .find_all_references_task_sources
16916                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16917                {
16918                    editor.find_all_references_task_sources.remove(i);
16919                }
16920            });
16921
16922            let Some(locations) = references.await? else {
16923                return anyhow::Ok(Navigated::No);
16924            };
16925            let mut locations = cx.update(|_, cx| {
16926                locations
16927                    .into_iter()
16928                    .map(|location| {
16929                        let buffer = location.buffer.read(cx);
16930                        (location.buffer, location.range.to_point(buffer))
16931                    })
16932                    .into_group_map()
16933            })?;
16934            if locations.is_empty() {
16935                return anyhow::Ok(Navigated::No);
16936            }
16937            for ranges in locations.values_mut() {
16938                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16939                ranges.dedup();
16940            }
16941
16942            workspace.update_in(cx, |workspace, window, cx| {
16943                let target = locations
16944                    .iter()
16945                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16946                    .map(|(buffer, location)| {
16947                        buffer
16948                            .read(cx)
16949                            .text_for_range(location.clone())
16950                            .collect::<String>()
16951                    })
16952                    .filter(|text| !text.contains('\n'))
16953                    .unique()
16954                    .take(3)
16955                    .join(", ");
16956                let title = if target.is_empty() {
16957                    "References".to_owned()
16958                } else {
16959                    format!("References to {target}")
16960                };
16961                Self::open_locations_in_multibuffer(
16962                    workspace,
16963                    locations,
16964                    title,
16965                    false,
16966                    MultibufferSelectionMode::First,
16967                    window,
16968                    cx,
16969                );
16970                Navigated::Yes
16971            })
16972        }))
16973    }
16974
16975    /// Opens a multibuffer with the given project locations in it
16976    pub fn open_locations_in_multibuffer(
16977        workspace: &mut Workspace,
16978        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16979        title: String,
16980        split: bool,
16981        multibuffer_selection_mode: MultibufferSelectionMode,
16982        window: &mut Window,
16983        cx: &mut Context<Workspace>,
16984    ) {
16985        if locations.is_empty() {
16986            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16987            return;
16988        }
16989
16990        let capability = workspace.project().read(cx).capability();
16991        let mut ranges = <Vec<Range<Anchor>>>::new();
16992
16993        // a key to find existing multibuffer editors with the same set of locations
16994        // to prevent us from opening more and more multibuffer tabs for searches and the like
16995        let mut key = (title.clone(), vec![]);
16996        let excerpt_buffer = cx.new(|cx| {
16997            let key = &mut key.1;
16998            let mut multibuffer = MultiBuffer::new(capability);
16999            for (buffer, mut ranges_for_buffer) in locations {
17000                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17001                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17002                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17003                    PathKey::for_buffer(&buffer, cx),
17004                    buffer.clone(),
17005                    ranges_for_buffer,
17006                    multibuffer_context_lines(cx),
17007                    cx,
17008                );
17009                ranges.extend(new_ranges)
17010            }
17011
17012            multibuffer.with_title(title)
17013        });
17014        let existing = workspace.active_pane().update(cx, |pane, cx| {
17015            pane.items()
17016                .filter_map(|item| item.downcast::<Editor>())
17017                .find(|editor| {
17018                    editor
17019                        .read(cx)
17020                        .lookup_key
17021                        .as_ref()
17022                        .and_then(|it| {
17023                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17024                        })
17025                        .is_some_and(|it| *it == key)
17026                })
17027        });
17028        let editor = existing.unwrap_or_else(|| {
17029            cx.new(|cx| {
17030                let mut editor = Editor::for_multibuffer(
17031                    excerpt_buffer,
17032                    Some(workspace.project().clone()),
17033                    window,
17034                    cx,
17035                );
17036                editor.lookup_key = Some(Box::new(key));
17037                editor
17038            })
17039        });
17040        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17041            MultibufferSelectionMode::First => {
17042                if let Some(first_range) = ranges.first() {
17043                    editor.change_selections(
17044                        SelectionEffects::no_scroll(),
17045                        window,
17046                        cx,
17047                        |selections| {
17048                            selections.clear_disjoint();
17049                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17050                        },
17051                    );
17052                }
17053                editor.highlight_background::<Self>(
17054                    &ranges,
17055                    |theme| theme.colors().editor_highlighted_line_background,
17056                    cx,
17057                );
17058            }
17059            MultibufferSelectionMode::All => {
17060                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17061                    selections.clear_disjoint();
17062                    selections.select_anchor_ranges(ranges);
17063                });
17064            }
17065        });
17066
17067        let item = Box::new(editor);
17068        let item_id = item.item_id();
17069
17070        if split {
17071            let pane = workspace.adjacent_pane(window, cx);
17072            workspace.add_item(pane, item, None, true, true, window, cx);
17073        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17074            let (preview_item_id, preview_item_idx) =
17075                workspace.active_pane().read_with(cx, |pane, _| {
17076                    (pane.preview_item_id(), pane.preview_item_idx())
17077                });
17078
17079            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17080
17081            if let Some(preview_item_id) = preview_item_id {
17082                workspace.active_pane().update(cx, |pane, cx| {
17083                    pane.remove_item(preview_item_id, false, false, window, cx);
17084                });
17085            }
17086        } else {
17087            workspace.add_item_to_active_pane(item, None, true, window, cx);
17088        }
17089        workspace.active_pane().update(cx, |pane, cx| {
17090            pane.set_preview_item_id(Some(item_id), cx);
17091        });
17092    }
17093
17094    pub fn rename(
17095        &mut self,
17096        _: &Rename,
17097        window: &mut Window,
17098        cx: &mut Context<Self>,
17099    ) -> Option<Task<Result<()>>> {
17100        use language::ToOffset as _;
17101
17102        let provider = self.semantics_provider.clone()?;
17103        let selection = self.selections.newest_anchor().clone();
17104        let (cursor_buffer, cursor_buffer_position) = self
17105            .buffer
17106            .read(cx)
17107            .text_anchor_for_position(selection.head(), cx)?;
17108        let (tail_buffer, cursor_buffer_position_end) = self
17109            .buffer
17110            .read(cx)
17111            .text_anchor_for_position(selection.tail(), cx)?;
17112        if tail_buffer != cursor_buffer {
17113            return None;
17114        }
17115
17116        let snapshot = cursor_buffer.read(cx).snapshot();
17117        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17118        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17119        let prepare_rename = provider
17120            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17121            .unwrap_or_else(|| Task::ready(Ok(None)));
17122        drop(snapshot);
17123
17124        Some(cx.spawn_in(window, async move |this, cx| {
17125            let rename_range = if let Some(range) = prepare_rename.await? {
17126                Some(range)
17127            } else {
17128                this.update(cx, |this, cx| {
17129                    let buffer = this.buffer.read(cx).snapshot(cx);
17130                    let mut buffer_highlights = this
17131                        .document_highlights_for_position(selection.head(), &buffer)
17132                        .filter(|highlight| {
17133                            highlight.start.excerpt_id == selection.head().excerpt_id
17134                                && highlight.end.excerpt_id == selection.head().excerpt_id
17135                        });
17136                    buffer_highlights
17137                        .next()
17138                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17139                })?
17140            };
17141            if let Some(rename_range) = rename_range {
17142                this.update_in(cx, |this, window, cx| {
17143                    let snapshot = cursor_buffer.read(cx).snapshot();
17144                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17145                    let cursor_offset_in_rename_range =
17146                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17147                    let cursor_offset_in_rename_range_end =
17148                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17149
17150                    this.take_rename(false, window, cx);
17151                    let buffer = this.buffer.read(cx).read(cx);
17152                    let cursor_offset = selection.head().to_offset(&buffer);
17153                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17154                    let rename_end = rename_start + rename_buffer_range.len();
17155                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17156                    let mut old_highlight_id = None;
17157                    let old_name: Arc<str> = buffer
17158                        .chunks(rename_start..rename_end, true)
17159                        .map(|chunk| {
17160                            if old_highlight_id.is_none() {
17161                                old_highlight_id = chunk.syntax_highlight_id;
17162                            }
17163                            chunk.text
17164                        })
17165                        .collect::<String>()
17166                        .into();
17167
17168                    drop(buffer);
17169
17170                    // Position the selection in the rename editor so that it matches the current selection.
17171                    this.show_local_selections = false;
17172                    let rename_editor = cx.new(|cx| {
17173                        let mut editor = Editor::single_line(window, cx);
17174                        editor.buffer.update(cx, |buffer, cx| {
17175                            buffer.edit([(0..0, old_name.clone())], None, cx)
17176                        });
17177                        let rename_selection_range = match cursor_offset_in_rename_range
17178                            .cmp(&cursor_offset_in_rename_range_end)
17179                        {
17180                            Ordering::Equal => {
17181                                editor.select_all(&SelectAll, window, cx);
17182                                return editor;
17183                            }
17184                            Ordering::Less => {
17185                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17186                            }
17187                            Ordering::Greater => {
17188                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17189                            }
17190                        };
17191                        if rename_selection_range.end > old_name.len() {
17192                            editor.select_all(&SelectAll, window, cx);
17193                        } else {
17194                            editor.change_selections(Default::default(), window, cx, |s| {
17195                                s.select_ranges([rename_selection_range]);
17196                            });
17197                        }
17198                        editor
17199                    });
17200                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17201                        if e == &EditorEvent::Focused {
17202                            cx.emit(EditorEvent::FocusedIn)
17203                        }
17204                    })
17205                    .detach();
17206
17207                    let write_highlights =
17208                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17209                    let read_highlights =
17210                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17211                    let ranges = write_highlights
17212                        .iter()
17213                        .flat_map(|(_, ranges)| ranges.iter())
17214                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17215                        .cloned()
17216                        .collect();
17217
17218                    this.highlight_text::<Rename>(
17219                        ranges,
17220                        HighlightStyle {
17221                            fade_out: Some(0.6),
17222                            ..Default::default()
17223                        },
17224                        cx,
17225                    );
17226                    let rename_focus_handle = rename_editor.focus_handle(cx);
17227                    window.focus(&rename_focus_handle);
17228                    let block_id = this.insert_blocks(
17229                        [BlockProperties {
17230                            style: BlockStyle::Flex,
17231                            placement: BlockPlacement::Below(range.start),
17232                            height: Some(1),
17233                            render: Arc::new({
17234                                let rename_editor = rename_editor.clone();
17235                                move |cx: &mut BlockContext| {
17236                                    let mut text_style = cx.editor_style.text.clone();
17237                                    if let Some(highlight_style) = old_highlight_id
17238                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17239                                    {
17240                                        text_style = text_style.highlight(highlight_style);
17241                                    }
17242                                    div()
17243                                        .block_mouse_except_scroll()
17244                                        .pl(cx.anchor_x)
17245                                        .child(EditorElement::new(
17246                                            &rename_editor,
17247                                            EditorStyle {
17248                                                background: cx.theme().system().transparent,
17249                                                local_player: cx.editor_style.local_player,
17250                                                text: text_style,
17251                                                scrollbar_width: cx.editor_style.scrollbar_width,
17252                                                syntax: cx.editor_style.syntax.clone(),
17253                                                status: cx.editor_style.status.clone(),
17254                                                inlay_hints_style: HighlightStyle {
17255                                                    font_weight: Some(FontWeight::BOLD),
17256                                                    ..make_inlay_hints_style(cx.app)
17257                                                },
17258                                                edit_prediction_styles: make_suggestion_styles(
17259                                                    cx.app,
17260                                                ),
17261                                                ..EditorStyle::default()
17262                                            },
17263                                        ))
17264                                        .into_any_element()
17265                                }
17266                            }),
17267                            priority: 0,
17268                        }],
17269                        Some(Autoscroll::fit()),
17270                        cx,
17271                    )[0];
17272                    this.pending_rename = Some(RenameState {
17273                        range,
17274                        old_name,
17275                        editor: rename_editor,
17276                        block_id,
17277                    });
17278                })?;
17279            }
17280
17281            Ok(())
17282        }))
17283    }
17284
17285    pub fn confirm_rename(
17286        &mut self,
17287        _: &ConfirmRename,
17288        window: &mut Window,
17289        cx: &mut Context<Self>,
17290    ) -> Option<Task<Result<()>>> {
17291        let rename = self.take_rename(false, window, cx)?;
17292        let workspace = self.workspace()?.downgrade();
17293        let (buffer, start) = self
17294            .buffer
17295            .read(cx)
17296            .text_anchor_for_position(rename.range.start, cx)?;
17297        let (end_buffer, _) = self
17298            .buffer
17299            .read(cx)
17300            .text_anchor_for_position(rename.range.end, cx)?;
17301        if buffer != end_buffer {
17302            return None;
17303        }
17304
17305        let old_name = rename.old_name;
17306        let new_name = rename.editor.read(cx).text(cx);
17307
17308        let rename = self.semantics_provider.as_ref()?.perform_rename(
17309            &buffer,
17310            start,
17311            new_name.clone(),
17312            cx,
17313        )?;
17314
17315        Some(cx.spawn_in(window, async move |editor, cx| {
17316            let project_transaction = rename.await?;
17317            Self::open_project_transaction(
17318                &editor,
17319                workspace,
17320                project_transaction,
17321                format!("Rename: {}{}", old_name, new_name),
17322                cx,
17323            )
17324            .await?;
17325
17326            editor.update(cx, |editor, cx| {
17327                editor.refresh_document_highlights(cx);
17328            })?;
17329            Ok(())
17330        }))
17331    }
17332
17333    fn take_rename(
17334        &mut self,
17335        moving_cursor: bool,
17336        window: &mut Window,
17337        cx: &mut Context<Self>,
17338    ) -> Option<RenameState> {
17339        let rename = self.pending_rename.take()?;
17340        if rename.editor.focus_handle(cx).is_focused(window) {
17341            window.focus(&self.focus_handle);
17342        }
17343
17344        self.remove_blocks(
17345            [rename.block_id].into_iter().collect(),
17346            Some(Autoscroll::fit()),
17347            cx,
17348        );
17349        self.clear_highlights::<Rename>(cx);
17350        self.show_local_selections = true;
17351
17352        if moving_cursor {
17353            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17354                editor
17355                    .selections
17356                    .newest::<usize>(&editor.display_snapshot(cx))
17357                    .head()
17358            });
17359
17360            // Update the selection to match the position of the selection inside
17361            // the rename editor.
17362            let snapshot = self.buffer.read(cx).read(cx);
17363            let rename_range = rename.range.to_offset(&snapshot);
17364            let cursor_in_editor = snapshot
17365                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17366                .min(rename_range.end);
17367            drop(snapshot);
17368
17369            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17370                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17371            });
17372        } else {
17373            self.refresh_document_highlights(cx);
17374        }
17375
17376        Some(rename)
17377    }
17378
17379    pub fn pending_rename(&self) -> Option<&RenameState> {
17380        self.pending_rename.as_ref()
17381    }
17382
17383    fn format(
17384        &mut self,
17385        _: &Format,
17386        window: &mut Window,
17387        cx: &mut Context<Self>,
17388    ) -> Option<Task<Result<()>>> {
17389        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17390
17391        let project = match &self.project {
17392            Some(project) => project.clone(),
17393            None => return None,
17394        };
17395
17396        Some(self.perform_format(
17397            project,
17398            FormatTrigger::Manual,
17399            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17400            window,
17401            cx,
17402        ))
17403    }
17404
17405    fn format_selections(
17406        &mut self,
17407        _: &FormatSelections,
17408        window: &mut Window,
17409        cx: &mut Context<Self>,
17410    ) -> Option<Task<Result<()>>> {
17411        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17412
17413        let project = match &self.project {
17414            Some(project) => project.clone(),
17415            None => return None,
17416        };
17417
17418        let ranges = self
17419            .selections
17420            .all_adjusted(&self.display_snapshot(cx))
17421            .into_iter()
17422            .map(|selection| selection.range())
17423            .collect_vec();
17424
17425        Some(self.perform_format(
17426            project,
17427            FormatTrigger::Manual,
17428            FormatTarget::Ranges(ranges),
17429            window,
17430            cx,
17431        ))
17432    }
17433
17434    fn perform_format(
17435        &mut self,
17436        project: Entity<Project>,
17437        trigger: FormatTrigger,
17438        target: FormatTarget,
17439        window: &mut Window,
17440        cx: &mut Context<Self>,
17441    ) -> Task<Result<()>> {
17442        let buffer = self.buffer.clone();
17443        let (buffers, target) = match target {
17444            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17445            FormatTarget::Ranges(selection_ranges) => {
17446                let multi_buffer = buffer.read(cx);
17447                let snapshot = multi_buffer.read(cx);
17448                let mut buffers = HashSet::default();
17449                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17450                    BTreeMap::new();
17451                for selection_range in selection_ranges {
17452                    for (buffer, buffer_range, _) in
17453                        snapshot.range_to_buffer_ranges(selection_range)
17454                    {
17455                        let buffer_id = buffer.remote_id();
17456                        let start = buffer.anchor_before(buffer_range.start);
17457                        let end = buffer.anchor_after(buffer_range.end);
17458                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17459                        buffer_id_to_ranges
17460                            .entry(buffer_id)
17461                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17462                            .or_insert_with(|| vec![start..end]);
17463                    }
17464                }
17465                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17466            }
17467        };
17468
17469        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17470        let selections_prev = transaction_id_prev
17471            .and_then(|transaction_id_prev| {
17472                // default to selections as they were after the last edit, if we have them,
17473                // instead of how they are now.
17474                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17475                // will take you back to where you made the last edit, instead of staying where you scrolled
17476                self.selection_history
17477                    .transaction(transaction_id_prev)
17478                    .map(|t| t.0.clone())
17479            })
17480            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17481
17482        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17483        let format = project.update(cx, |project, cx| {
17484            project.format(buffers, target, true, trigger, cx)
17485        });
17486
17487        cx.spawn_in(window, async move |editor, cx| {
17488            let transaction = futures::select_biased! {
17489                transaction = format.log_err().fuse() => transaction,
17490                () = timeout => {
17491                    log::warn!("timed out waiting for formatting");
17492                    None
17493                }
17494            };
17495
17496            buffer
17497                .update(cx, |buffer, cx| {
17498                    if let Some(transaction) = transaction
17499                        && !buffer.is_singleton()
17500                    {
17501                        buffer.push_transaction(&transaction.0, cx);
17502                    }
17503                    cx.notify();
17504                })
17505                .ok();
17506
17507            if let Some(transaction_id_now) =
17508                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17509            {
17510                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17511                if has_new_transaction {
17512                    _ = editor.update(cx, |editor, _| {
17513                        editor
17514                            .selection_history
17515                            .insert_transaction(transaction_id_now, selections_prev);
17516                    });
17517                }
17518            }
17519
17520            Ok(())
17521        })
17522    }
17523
17524    fn organize_imports(
17525        &mut self,
17526        _: &OrganizeImports,
17527        window: &mut Window,
17528        cx: &mut Context<Self>,
17529    ) -> Option<Task<Result<()>>> {
17530        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17531        let project = match &self.project {
17532            Some(project) => project.clone(),
17533            None => return None,
17534        };
17535        Some(self.perform_code_action_kind(
17536            project,
17537            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17538            window,
17539            cx,
17540        ))
17541    }
17542
17543    fn perform_code_action_kind(
17544        &mut self,
17545        project: Entity<Project>,
17546        kind: CodeActionKind,
17547        window: &mut Window,
17548        cx: &mut Context<Self>,
17549    ) -> Task<Result<()>> {
17550        let buffer = self.buffer.clone();
17551        let buffers = buffer.read(cx).all_buffers();
17552        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17553        let apply_action = project.update(cx, |project, cx| {
17554            project.apply_code_action_kind(buffers, kind, true, cx)
17555        });
17556        cx.spawn_in(window, async move |_, cx| {
17557            let transaction = futures::select_biased! {
17558                () = timeout => {
17559                    log::warn!("timed out waiting for executing code action");
17560                    None
17561                }
17562                transaction = apply_action.log_err().fuse() => transaction,
17563            };
17564            buffer
17565                .update(cx, |buffer, cx| {
17566                    // check if we need this
17567                    if let Some(transaction) = transaction
17568                        && !buffer.is_singleton()
17569                    {
17570                        buffer.push_transaction(&transaction.0, cx);
17571                    }
17572                    cx.notify();
17573                })
17574                .ok();
17575            Ok(())
17576        })
17577    }
17578
17579    pub fn restart_language_server(
17580        &mut self,
17581        _: &RestartLanguageServer,
17582        _: &mut Window,
17583        cx: &mut Context<Self>,
17584    ) {
17585        if let Some(project) = self.project.clone() {
17586            self.buffer.update(cx, |multi_buffer, cx| {
17587                project.update(cx, |project, cx| {
17588                    project.restart_language_servers_for_buffers(
17589                        multi_buffer.all_buffers().into_iter().collect(),
17590                        HashSet::default(),
17591                        cx,
17592                    );
17593                });
17594            })
17595        }
17596    }
17597
17598    pub fn stop_language_server(
17599        &mut self,
17600        _: &StopLanguageServer,
17601        _: &mut Window,
17602        cx: &mut Context<Self>,
17603    ) {
17604        if let Some(project) = self.project.clone() {
17605            self.buffer.update(cx, |multi_buffer, cx| {
17606                project.update(cx, |project, cx| {
17607                    project.stop_language_servers_for_buffers(
17608                        multi_buffer.all_buffers().into_iter().collect(),
17609                        HashSet::default(),
17610                        cx,
17611                    );
17612                });
17613            });
17614            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17615        }
17616    }
17617
17618    fn cancel_language_server_work(
17619        workspace: &mut Workspace,
17620        _: &actions::CancelLanguageServerWork,
17621        _: &mut Window,
17622        cx: &mut Context<Workspace>,
17623    ) {
17624        let project = workspace.project();
17625        let buffers = workspace
17626            .active_item(cx)
17627            .and_then(|item| item.act_as::<Editor>(cx))
17628            .map_or(HashSet::default(), |editor| {
17629                editor.read(cx).buffer.read(cx).all_buffers()
17630            });
17631        project.update(cx, |project, cx| {
17632            project.cancel_language_server_work_for_buffers(buffers, cx);
17633        });
17634    }
17635
17636    fn show_character_palette(
17637        &mut self,
17638        _: &ShowCharacterPalette,
17639        window: &mut Window,
17640        _: &mut Context<Self>,
17641    ) {
17642        window.show_character_palette();
17643    }
17644
17645    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17646        if !self.diagnostics_enabled() {
17647            return;
17648        }
17649
17650        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17651            let buffer = self.buffer.read(cx).snapshot(cx);
17652            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17653            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17654            let is_valid = buffer
17655                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17656                .any(|entry| {
17657                    entry.diagnostic.is_primary
17658                        && !entry.range.is_empty()
17659                        && entry.range.start == primary_range_start
17660                        && entry.diagnostic.message == active_diagnostics.active_message
17661                });
17662
17663            if !is_valid {
17664                self.dismiss_diagnostics(cx);
17665            }
17666        }
17667    }
17668
17669    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17670        match &self.active_diagnostics {
17671            ActiveDiagnostic::Group(group) => Some(group),
17672            _ => None,
17673        }
17674    }
17675
17676    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17677        if !self.diagnostics_enabled() {
17678            return;
17679        }
17680        self.dismiss_diagnostics(cx);
17681        self.active_diagnostics = ActiveDiagnostic::All;
17682    }
17683
17684    fn activate_diagnostics(
17685        &mut self,
17686        buffer_id: BufferId,
17687        diagnostic: DiagnosticEntryRef<'_, usize>,
17688        window: &mut Window,
17689        cx: &mut Context<Self>,
17690    ) {
17691        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17692            return;
17693        }
17694        self.dismiss_diagnostics(cx);
17695        let snapshot = self.snapshot(window, cx);
17696        let buffer = self.buffer.read(cx).snapshot(cx);
17697        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17698            return;
17699        };
17700
17701        let diagnostic_group = buffer
17702            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17703            .collect::<Vec<_>>();
17704
17705        let blocks =
17706            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17707
17708        let blocks = self.display_map.update(cx, |display_map, cx| {
17709            display_map.insert_blocks(blocks, cx).into_iter().collect()
17710        });
17711        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17712            active_range: buffer.anchor_before(diagnostic.range.start)
17713                ..buffer.anchor_after(diagnostic.range.end),
17714            active_message: diagnostic.diagnostic.message.clone(),
17715            group_id: diagnostic.diagnostic.group_id,
17716            blocks,
17717        });
17718        cx.notify();
17719    }
17720
17721    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17722        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17723            return;
17724        };
17725
17726        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17727        if let ActiveDiagnostic::Group(group) = prev {
17728            self.display_map.update(cx, |display_map, cx| {
17729                display_map.remove_blocks(group.blocks, cx);
17730            });
17731            cx.notify();
17732        }
17733    }
17734
17735    /// Disable inline diagnostics rendering for this editor.
17736    pub fn disable_inline_diagnostics(&mut self) {
17737        self.inline_diagnostics_enabled = false;
17738        self.inline_diagnostics_update = Task::ready(());
17739        self.inline_diagnostics.clear();
17740    }
17741
17742    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17743        self.diagnostics_enabled = false;
17744        self.dismiss_diagnostics(cx);
17745        self.inline_diagnostics_update = Task::ready(());
17746        self.inline_diagnostics.clear();
17747    }
17748
17749    pub fn disable_word_completions(&mut self) {
17750        self.word_completions_enabled = false;
17751    }
17752
17753    pub fn diagnostics_enabled(&self) -> bool {
17754        self.diagnostics_enabled && self.mode.is_full()
17755    }
17756
17757    pub fn inline_diagnostics_enabled(&self) -> bool {
17758        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17759    }
17760
17761    pub fn show_inline_diagnostics(&self) -> bool {
17762        self.show_inline_diagnostics
17763    }
17764
17765    pub fn toggle_inline_diagnostics(
17766        &mut self,
17767        _: &ToggleInlineDiagnostics,
17768        window: &mut Window,
17769        cx: &mut Context<Editor>,
17770    ) {
17771        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17772        self.refresh_inline_diagnostics(false, window, cx);
17773    }
17774
17775    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17776        self.diagnostics_max_severity = severity;
17777        self.display_map.update(cx, |display_map, _| {
17778            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17779        });
17780    }
17781
17782    pub fn toggle_diagnostics(
17783        &mut self,
17784        _: &ToggleDiagnostics,
17785        window: &mut Window,
17786        cx: &mut Context<Editor>,
17787    ) {
17788        if !self.diagnostics_enabled() {
17789            return;
17790        }
17791
17792        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17793            EditorSettings::get_global(cx)
17794                .diagnostics_max_severity
17795                .filter(|severity| severity != &DiagnosticSeverity::Off)
17796                .unwrap_or(DiagnosticSeverity::Hint)
17797        } else {
17798            DiagnosticSeverity::Off
17799        };
17800        self.set_max_diagnostics_severity(new_severity, cx);
17801        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17802            self.active_diagnostics = ActiveDiagnostic::None;
17803            self.inline_diagnostics_update = Task::ready(());
17804            self.inline_diagnostics.clear();
17805        } else {
17806            self.refresh_inline_diagnostics(false, window, cx);
17807        }
17808
17809        cx.notify();
17810    }
17811
17812    pub fn toggle_minimap(
17813        &mut self,
17814        _: &ToggleMinimap,
17815        window: &mut Window,
17816        cx: &mut Context<Editor>,
17817    ) {
17818        if self.supports_minimap(cx) {
17819            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17820        }
17821    }
17822
17823    fn refresh_inline_diagnostics(
17824        &mut self,
17825        debounce: bool,
17826        window: &mut Window,
17827        cx: &mut Context<Self>,
17828    ) {
17829        let max_severity = ProjectSettings::get_global(cx)
17830            .diagnostics
17831            .inline
17832            .max_severity
17833            .unwrap_or(self.diagnostics_max_severity);
17834
17835        if !self.inline_diagnostics_enabled()
17836            || !self.show_inline_diagnostics
17837            || max_severity == DiagnosticSeverity::Off
17838        {
17839            self.inline_diagnostics_update = Task::ready(());
17840            self.inline_diagnostics.clear();
17841            return;
17842        }
17843
17844        let debounce_ms = ProjectSettings::get_global(cx)
17845            .diagnostics
17846            .inline
17847            .update_debounce_ms;
17848        let debounce = if debounce && debounce_ms > 0 {
17849            Some(Duration::from_millis(debounce_ms))
17850        } else {
17851            None
17852        };
17853        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17854            if let Some(debounce) = debounce {
17855                cx.background_executor().timer(debounce).await;
17856            }
17857            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17858                editor
17859                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17860                    .ok()
17861            }) else {
17862                return;
17863            };
17864
17865            let new_inline_diagnostics = cx
17866                .background_spawn(async move {
17867                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17868                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17869                        let message = diagnostic_entry
17870                            .diagnostic
17871                            .message
17872                            .split_once('\n')
17873                            .map(|(line, _)| line)
17874                            .map(SharedString::new)
17875                            .unwrap_or_else(|| {
17876                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17877                            });
17878                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17879                        let (Ok(i) | Err(i)) = inline_diagnostics
17880                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17881                        inline_diagnostics.insert(
17882                            i,
17883                            (
17884                                start_anchor,
17885                                InlineDiagnostic {
17886                                    message,
17887                                    group_id: diagnostic_entry.diagnostic.group_id,
17888                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17889                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17890                                    severity: diagnostic_entry.diagnostic.severity,
17891                                },
17892                            ),
17893                        );
17894                    }
17895                    inline_diagnostics
17896                })
17897                .await;
17898
17899            editor
17900                .update(cx, |editor, cx| {
17901                    editor.inline_diagnostics = new_inline_diagnostics;
17902                    cx.notify();
17903                })
17904                .ok();
17905        });
17906    }
17907
17908    fn pull_diagnostics(
17909        &mut self,
17910        buffer_id: Option<BufferId>,
17911        window: &Window,
17912        cx: &mut Context<Self>,
17913    ) -> Option<()> {
17914        if self.ignore_lsp_data() {
17915            return None;
17916        }
17917        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17918            .diagnostics
17919            .lsp_pull_diagnostics;
17920        if !pull_diagnostics_settings.enabled {
17921            return None;
17922        }
17923        let project = self.project()?.downgrade();
17924        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17925        let mut buffers = self.buffer.read(cx).all_buffers();
17926        buffers.retain(|buffer| {
17927            let buffer_id_to_retain = buffer.read(cx).remote_id();
17928            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17929                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17930        });
17931        if buffers.is_empty() {
17932            self.pull_diagnostics_task = Task::ready(());
17933            return None;
17934        }
17935
17936        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17937            cx.background_executor().timer(debounce).await;
17938
17939            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17940                buffers
17941                    .into_iter()
17942                    .filter_map(|buffer| {
17943                        project
17944                            .update(cx, |project, cx| {
17945                                project.lsp_store().update(cx, |lsp_store, cx| {
17946                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17947                                })
17948                            })
17949                            .ok()
17950                    })
17951                    .collect::<FuturesUnordered<_>>()
17952            }) else {
17953                return;
17954            };
17955
17956            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17957                match pull_task {
17958                    Ok(()) => {
17959                        if editor
17960                            .update_in(cx, |editor, window, cx| {
17961                                editor.update_diagnostics_state(window, cx);
17962                            })
17963                            .is_err()
17964                        {
17965                            return;
17966                        }
17967                    }
17968                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17969                }
17970            }
17971        });
17972
17973        Some(())
17974    }
17975
17976    pub fn set_selections_from_remote(
17977        &mut self,
17978        selections: Vec<Selection<Anchor>>,
17979        pending_selection: Option<Selection<Anchor>>,
17980        window: &mut Window,
17981        cx: &mut Context<Self>,
17982    ) {
17983        let old_cursor_position = self.selections.newest_anchor().head();
17984        self.selections.change_with(cx, |s| {
17985            s.select_anchors(selections);
17986            if let Some(pending_selection) = pending_selection {
17987                s.set_pending(pending_selection, SelectMode::Character);
17988            } else {
17989                s.clear_pending();
17990            }
17991        });
17992        self.selections_did_change(
17993            false,
17994            &old_cursor_position,
17995            SelectionEffects::default(),
17996            window,
17997            cx,
17998        );
17999    }
18000
18001    pub fn transact(
18002        &mut self,
18003        window: &mut Window,
18004        cx: &mut Context<Self>,
18005        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18006    ) -> Option<TransactionId> {
18007        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18008            this.start_transaction_at(Instant::now(), window, cx);
18009            update(this, window, cx);
18010            this.end_transaction_at(Instant::now(), cx)
18011        })
18012    }
18013
18014    pub fn start_transaction_at(
18015        &mut self,
18016        now: Instant,
18017        window: &mut Window,
18018        cx: &mut Context<Self>,
18019    ) -> Option<TransactionId> {
18020        self.end_selection(window, cx);
18021        if let Some(tx_id) = self
18022            .buffer
18023            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18024        {
18025            self.selection_history
18026                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18027            cx.emit(EditorEvent::TransactionBegun {
18028                transaction_id: tx_id,
18029            });
18030            Some(tx_id)
18031        } else {
18032            None
18033        }
18034    }
18035
18036    pub fn end_transaction_at(
18037        &mut self,
18038        now: Instant,
18039        cx: &mut Context<Self>,
18040    ) -> Option<TransactionId> {
18041        if let Some(transaction_id) = self
18042            .buffer
18043            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18044        {
18045            if let Some((_, end_selections)) =
18046                self.selection_history.transaction_mut(transaction_id)
18047            {
18048                *end_selections = Some(self.selections.disjoint_anchors_arc());
18049            } else {
18050                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18051            }
18052
18053            cx.emit(EditorEvent::Edited { transaction_id });
18054            Some(transaction_id)
18055        } else {
18056            None
18057        }
18058    }
18059
18060    pub fn modify_transaction_selection_history(
18061        &mut self,
18062        transaction_id: TransactionId,
18063        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18064    ) -> bool {
18065        self.selection_history
18066            .transaction_mut(transaction_id)
18067            .map(modify)
18068            .is_some()
18069    }
18070
18071    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18072        if self.selection_mark_mode {
18073            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18074                s.move_with(|_, sel| {
18075                    sel.collapse_to(sel.head(), SelectionGoal::None);
18076                });
18077            })
18078        }
18079        self.selection_mark_mode = true;
18080        cx.notify();
18081    }
18082
18083    pub fn swap_selection_ends(
18084        &mut self,
18085        _: &actions::SwapSelectionEnds,
18086        window: &mut Window,
18087        cx: &mut Context<Self>,
18088    ) {
18089        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18090            s.move_with(|_, sel| {
18091                if sel.start != sel.end {
18092                    sel.reversed = !sel.reversed
18093                }
18094            });
18095        });
18096        self.request_autoscroll(Autoscroll::newest(), cx);
18097        cx.notify();
18098    }
18099
18100    pub fn toggle_focus(
18101        workspace: &mut Workspace,
18102        _: &actions::ToggleFocus,
18103        window: &mut Window,
18104        cx: &mut Context<Workspace>,
18105    ) {
18106        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18107            return;
18108        };
18109        workspace.activate_item(&item, true, true, window, cx);
18110    }
18111
18112    pub fn toggle_fold(
18113        &mut self,
18114        _: &actions::ToggleFold,
18115        window: &mut Window,
18116        cx: &mut Context<Self>,
18117    ) {
18118        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18119            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18120            let selection = self.selections.newest::<Point>(&display_map);
18121
18122            let range = if selection.is_empty() {
18123                let point = selection.head().to_display_point(&display_map);
18124                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18125                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18126                    .to_point(&display_map);
18127                start..end
18128            } else {
18129                selection.range()
18130            };
18131            if display_map.folds_in_range(range).next().is_some() {
18132                self.unfold_lines(&Default::default(), window, cx)
18133            } else {
18134                self.fold(&Default::default(), window, cx)
18135            }
18136        } else {
18137            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18138            let buffer_ids: HashSet<_> = self
18139                .selections
18140                .disjoint_anchor_ranges()
18141                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18142                .collect();
18143
18144            let should_unfold = buffer_ids
18145                .iter()
18146                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18147
18148            for buffer_id in buffer_ids {
18149                if should_unfold {
18150                    self.unfold_buffer(buffer_id, cx);
18151                } else {
18152                    self.fold_buffer(buffer_id, cx);
18153                }
18154            }
18155        }
18156    }
18157
18158    pub fn toggle_fold_recursive(
18159        &mut self,
18160        _: &actions::ToggleFoldRecursive,
18161        window: &mut Window,
18162        cx: &mut Context<Self>,
18163    ) {
18164        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18165
18166        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18167        let range = if selection.is_empty() {
18168            let point = selection.head().to_display_point(&display_map);
18169            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18170            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18171                .to_point(&display_map);
18172            start..end
18173        } else {
18174            selection.range()
18175        };
18176        if display_map.folds_in_range(range).next().is_some() {
18177            self.unfold_recursive(&Default::default(), window, cx)
18178        } else {
18179            self.fold_recursive(&Default::default(), window, cx)
18180        }
18181    }
18182
18183    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18184        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18185            let mut to_fold = Vec::new();
18186            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18187            let selections = self.selections.all_adjusted(&display_map);
18188
18189            for selection in selections {
18190                let range = selection.range().sorted();
18191                let buffer_start_row = range.start.row;
18192
18193                if range.start.row != range.end.row {
18194                    let mut found = false;
18195                    let mut row = range.start.row;
18196                    while row <= range.end.row {
18197                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18198                        {
18199                            found = true;
18200                            row = crease.range().end.row + 1;
18201                            to_fold.push(crease);
18202                        } else {
18203                            row += 1
18204                        }
18205                    }
18206                    if found {
18207                        continue;
18208                    }
18209                }
18210
18211                for row in (0..=range.start.row).rev() {
18212                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18213                        && crease.range().end.row >= buffer_start_row
18214                    {
18215                        to_fold.push(crease);
18216                        if row <= range.start.row {
18217                            break;
18218                        }
18219                    }
18220                }
18221            }
18222
18223            self.fold_creases(to_fold, true, window, cx);
18224        } else {
18225            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18226            let buffer_ids = self
18227                .selections
18228                .disjoint_anchor_ranges()
18229                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18230                .collect::<HashSet<_>>();
18231            for buffer_id in buffer_ids {
18232                self.fold_buffer(buffer_id, cx);
18233            }
18234        }
18235    }
18236
18237    pub fn toggle_fold_all(
18238        &mut self,
18239        _: &actions::ToggleFoldAll,
18240        window: &mut Window,
18241        cx: &mut Context<Self>,
18242    ) {
18243        if self.buffer.read(cx).is_singleton() {
18244            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18245            let has_folds = display_map
18246                .folds_in_range(0..display_map.buffer_snapshot().len())
18247                .next()
18248                .is_some();
18249
18250            if has_folds {
18251                self.unfold_all(&actions::UnfoldAll, window, cx);
18252            } else {
18253                self.fold_all(&actions::FoldAll, window, cx);
18254            }
18255        } else {
18256            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18257            let should_unfold = buffer_ids
18258                .iter()
18259                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18260
18261            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18262                editor
18263                    .update_in(cx, |editor, _, cx| {
18264                        for buffer_id in buffer_ids {
18265                            if should_unfold {
18266                                editor.unfold_buffer(buffer_id, cx);
18267                            } else {
18268                                editor.fold_buffer(buffer_id, cx);
18269                            }
18270                        }
18271                    })
18272                    .ok();
18273            });
18274        }
18275    }
18276
18277    fn fold_at_level(
18278        &mut self,
18279        fold_at: &FoldAtLevel,
18280        window: &mut Window,
18281        cx: &mut Context<Self>,
18282    ) {
18283        if !self.buffer.read(cx).is_singleton() {
18284            return;
18285        }
18286
18287        let fold_at_level = fold_at.0;
18288        let snapshot = self.buffer.read(cx).snapshot(cx);
18289        let mut to_fold = Vec::new();
18290        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18291
18292        let row_ranges_to_keep: Vec<Range<u32>> = self
18293            .selections
18294            .all::<Point>(&self.display_snapshot(cx))
18295            .into_iter()
18296            .map(|sel| sel.start.row..sel.end.row)
18297            .collect();
18298
18299        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18300            while start_row < end_row {
18301                match self
18302                    .snapshot(window, cx)
18303                    .crease_for_buffer_row(MultiBufferRow(start_row))
18304                {
18305                    Some(crease) => {
18306                        let nested_start_row = crease.range().start.row + 1;
18307                        let nested_end_row = crease.range().end.row;
18308
18309                        if current_level < fold_at_level {
18310                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18311                        } else if current_level == fold_at_level {
18312                            // Fold iff there is no selection completely contained within the fold region
18313                            if !row_ranges_to_keep.iter().any(|selection| {
18314                                selection.end >= nested_start_row
18315                                    && selection.start <= nested_end_row
18316                            }) {
18317                                to_fold.push(crease);
18318                            }
18319                        }
18320
18321                        start_row = nested_end_row + 1;
18322                    }
18323                    None => start_row += 1,
18324                }
18325            }
18326        }
18327
18328        self.fold_creases(to_fold, true, window, cx);
18329    }
18330
18331    pub fn fold_at_level_1(
18332        &mut self,
18333        _: &actions::FoldAtLevel1,
18334        window: &mut Window,
18335        cx: &mut Context<Self>,
18336    ) {
18337        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18338    }
18339
18340    pub fn fold_at_level_2(
18341        &mut self,
18342        _: &actions::FoldAtLevel2,
18343        window: &mut Window,
18344        cx: &mut Context<Self>,
18345    ) {
18346        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18347    }
18348
18349    pub fn fold_at_level_3(
18350        &mut self,
18351        _: &actions::FoldAtLevel3,
18352        window: &mut Window,
18353        cx: &mut Context<Self>,
18354    ) {
18355        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18356    }
18357
18358    pub fn fold_at_level_4(
18359        &mut self,
18360        _: &actions::FoldAtLevel4,
18361        window: &mut Window,
18362        cx: &mut Context<Self>,
18363    ) {
18364        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18365    }
18366
18367    pub fn fold_at_level_5(
18368        &mut self,
18369        _: &actions::FoldAtLevel5,
18370        window: &mut Window,
18371        cx: &mut Context<Self>,
18372    ) {
18373        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18374    }
18375
18376    pub fn fold_at_level_6(
18377        &mut self,
18378        _: &actions::FoldAtLevel6,
18379        window: &mut Window,
18380        cx: &mut Context<Self>,
18381    ) {
18382        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18383    }
18384
18385    pub fn fold_at_level_7(
18386        &mut self,
18387        _: &actions::FoldAtLevel7,
18388        window: &mut Window,
18389        cx: &mut Context<Self>,
18390    ) {
18391        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18392    }
18393
18394    pub fn fold_at_level_8(
18395        &mut self,
18396        _: &actions::FoldAtLevel8,
18397        window: &mut Window,
18398        cx: &mut Context<Self>,
18399    ) {
18400        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18401    }
18402
18403    pub fn fold_at_level_9(
18404        &mut self,
18405        _: &actions::FoldAtLevel9,
18406        window: &mut Window,
18407        cx: &mut Context<Self>,
18408    ) {
18409        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18410    }
18411
18412    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18413        if self.buffer.read(cx).is_singleton() {
18414            let mut fold_ranges = Vec::new();
18415            let snapshot = self.buffer.read(cx).snapshot(cx);
18416
18417            for row in 0..snapshot.max_row().0 {
18418                if let Some(foldable_range) = self
18419                    .snapshot(window, cx)
18420                    .crease_for_buffer_row(MultiBufferRow(row))
18421                {
18422                    fold_ranges.push(foldable_range);
18423                }
18424            }
18425
18426            self.fold_creases(fold_ranges, true, window, cx);
18427        } else {
18428            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18429                editor
18430                    .update_in(cx, |editor, _, cx| {
18431                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18432                            editor.fold_buffer(buffer_id, cx);
18433                        }
18434                    })
18435                    .ok();
18436            });
18437        }
18438    }
18439
18440    pub fn fold_function_bodies(
18441        &mut self,
18442        _: &actions::FoldFunctionBodies,
18443        window: &mut Window,
18444        cx: &mut Context<Self>,
18445    ) {
18446        let snapshot = self.buffer.read(cx).snapshot(cx);
18447
18448        let ranges = snapshot
18449            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18450            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18451            .collect::<Vec<_>>();
18452
18453        let creases = ranges
18454            .into_iter()
18455            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18456            .collect();
18457
18458        self.fold_creases(creases, true, window, cx);
18459    }
18460
18461    pub fn fold_recursive(
18462        &mut self,
18463        _: &actions::FoldRecursive,
18464        window: &mut Window,
18465        cx: &mut Context<Self>,
18466    ) {
18467        let mut to_fold = Vec::new();
18468        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18469        let selections = self.selections.all_adjusted(&display_map);
18470
18471        for selection in selections {
18472            let range = selection.range().sorted();
18473            let buffer_start_row = range.start.row;
18474
18475            if range.start.row != range.end.row {
18476                let mut found = false;
18477                for row in range.start.row..=range.end.row {
18478                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18479                        found = true;
18480                        to_fold.push(crease);
18481                    }
18482                }
18483                if found {
18484                    continue;
18485                }
18486            }
18487
18488            for row in (0..=range.start.row).rev() {
18489                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18490                    if crease.range().end.row >= buffer_start_row {
18491                        to_fold.push(crease);
18492                    } else {
18493                        break;
18494                    }
18495                }
18496            }
18497        }
18498
18499        self.fold_creases(to_fold, true, window, cx);
18500    }
18501
18502    pub fn fold_at(
18503        &mut self,
18504        buffer_row: MultiBufferRow,
18505        window: &mut Window,
18506        cx: &mut Context<Self>,
18507    ) {
18508        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18509
18510        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18511            let autoscroll = self
18512                .selections
18513                .all::<Point>(&display_map)
18514                .iter()
18515                .any(|selection| crease.range().overlaps(&selection.range()));
18516
18517            self.fold_creases(vec![crease], autoscroll, window, cx);
18518        }
18519    }
18520
18521    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18522        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18523            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18524            let buffer = display_map.buffer_snapshot();
18525            let selections = self.selections.all::<Point>(&display_map);
18526            let ranges = selections
18527                .iter()
18528                .map(|s| {
18529                    let range = s.display_range(&display_map).sorted();
18530                    let mut start = range.start.to_point(&display_map);
18531                    let mut end = range.end.to_point(&display_map);
18532                    start.column = 0;
18533                    end.column = buffer.line_len(MultiBufferRow(end.row));
18534                    start..end
18535                })
18536                .collect::<Vec<_>>();
18537
18538            self.unfold_ranges(&ranges, true, true, cx);
18539        } else {
18540            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18541            let buffer_ids = self
18542                .selections
18543                .disjoint_anchor_ranges()
18544                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18545                .collect::<HashSet<_>>();
18546            for buffer_id in buffer_ids {
18547                self.unfold_buffer(buffer_id, cx);
18548            }
18549        }
18550    }
18551
18552    pub fn unfold_recursive(
18553        &mut self,
18554        _: &UnfoldRecursive,
18555        _window: &mut Window,
18556        cx: &mut Context<Self>,
18557    ) {
18558        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18559        let selections = self.selections.all::<Point>(&display_map);
18560        let ranges = selections
18561            .iter()
18562            .map(|s| {
18563                let mut range = s.display_range(&display_map).sorted();
18564                *range.start.column_mut() = 0;
18565                *range.end.column_mut() = display_map.line_len(range.end.row());
18566                let start = range.start.to_point(&display_map);
18567                let end = range.end.to_point(&display_map);
18568                start..end
18569            })
18570            .collect::<Vec<_>>();
18571
18572        self.unfold_ranges(&ranges, true, true, cx);
18573    }
18574
18575    pub fn unfold_at(
18576        &mut self,
18577        buffer_row: MultiBufferRow,
18578        _window: &mut Window,
18579        cx: &mut Context<Self>,
18580    ) {
18581        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18582
18583        let intersection_range = Point::new(buffer_row.0, 0)
18584            ..Point::new(
18585                buffer_row.0,
18586                display_map.buffer_snapshot().line_len(buffer_row),
18587            );
18588
18589        let autoscroll = self
18590            .selections
18591            .all::<Point>(&display_map)
18592            .iter()
18593            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18594
18595        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18596    }
18597
18598    pub fn unfold_all(
18599        &mut self,
18600        _: &actions::UnfoldAll,
18601        _window: &mut Window,
18602        cx: &mut Context<Self>,
18603    ) {
18604        if self.buffer.read(cx).is_singleton() {
18605            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18606            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18607        } else {
18608            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18609                editor
18610                    .update(cx, |editor, cx| {
18611                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18612                            editor.unfold_buffer(buffer_id, cx);
18613                        }
18614                    })
18615                    .ok();
18616            });
18617        }
18618    }
18619
18620    pub fn fold_selected_ranges(
18621        &mut self,
18622        _: &FoldSelectedRanges,
18623        window: &mut Window,
18624        cx: &mut Context<Self>,
18625    ) {
18626        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18627        let selections = self.selections.all_adjusted(&display_map);
18628        let ranges = selections
18629            .into_iter()
18630            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18631            .collect::<Vec<_>>();
18632        self.fold_creases(ranges, true, window, cx);
18633    }
18634
18635    pub fn fold_ranges<T: ToOffset + Clone>(
18636        &mut self,
18637        ranges: Vec<Range<T>>,
18638        auto_scroll: bool,
18639        window: &mut Window,
18640        cx: &mut Context<Self>,
18641    ) {
18642        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18643        let ranges = ranges
18644            .into_iter()
18645            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18646            .collect::<Vec<_>>();
18647        self.fold_creases(ranges, auto_scroll, window, cx);
18648    }
18649
18650    pub fn fold_creases<T: ToOffset + Clone>(
18651        &mut self,
18652        creases: Vec<Crease<T>>,
18653        auto_scroll: bool,
18654        _window: &mut Window,
18655        cx: &mut Context<Self>,
18656    ) {
18657        if creases.is_empty() {
18658            return;
18659        }
18660
18661        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18662
18663        if auto_scroll {
18664            self.request_autoscroll(Autoscroll::fit(), cx);
18665        }
18666
18667        cx.notify();
18668
18669        self.scrollbar_marker_state.dirty = true;
18670        self.folds_did_change(cx);
18671    }
18672
18673    /// Removes any folds whose ranges intersect any of the given ranges.
18674    pub fn unfold_ranges<T: ToOffset + Clone>(
18675        &mut self,
18676        ranges: &[Range<T>],
18677        inclusive: bool,
18678        auto_scroll: bool,
18679        cx: &mut Context<Self>,
18680    ) {
18681        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18682            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18683        });
18684        self.folds_did_change(cx);
18685    }
18686
18687    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18688        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18689            return;
18690        }
18691        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18692        self.display_map.update(cx, |display_map, cx| {
18693            display_map.fold_buffers([buffer_id], cx)
18694        });
18695        cx.emit(EditorEvent::BufferFoldToggled {
18696            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18697            folded: true,
18698        });
18699        cx.notify();
18700    }
18701
18702    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18703        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18704            return;
18705        }
18706        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18707        self.display_map.update(cx, |display_map, cx| {
18708            display_map.unfold_buffers([buffer_id], cx);
18709        });
18710        cx.emit(EditorEvent::BufferFoldToggled {
18711            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18712            folded: false,
18713        });
18714        cx.notify();
18715    }
18716
18717    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18718        self.display_map.read(cx).is_buffer_folded(buffer)
18719    }
18720
18721    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18722        self.display_map.read(cx).folded_buffers()
18723    }
18724
18725    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18726        self.display_map.update(cx, |display_map, cx| {
18727            display_map.disable_header_for_buffer(buffer_id, cx);
18728        });
18729        cx.notify();
18730    }
18731
18732    /// Removes any folds with the given ranges.
18733    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18734        &mut self,
18735        ranges: &[Range<T>],
18736        type_id: TypeId,
18737        auto_scroll: bool,
18738        cx: &mut Context<Self>,
18739    ) {
18740        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18741            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18742        });
18743        self.folds_did_change(cx);
18744    }
18745
18746    fn remove_folds_with<T: ToOffset + Clone>(
18747        &mut self,
18748        ranges: &[Range<T>],
18749        auto_scroll: bool,
18750        cx: &mut Context<Self>,
18751        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18752    ) {
18753        if ranges.is_empty() {
18754            return;
18755        }
18756
18757        let mut buffers_affected = HashSet::default();
18758        let multi_buffer = self.buffer().read(cx);
18759        for range in ranges {
18760            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18761                buffers_affected.insert(buffer.read(cx).remote_id());
18762            };
18763        }
18764
18765        self.display_map.update(cx, update);
18766
18767        if auto_scroll {
18768            self.request_autoscroll(Autoscroll::fit(), cx);
18769        }
18770
18771        cx.notify();
18772        self.scrollbar_marker_state.dirty = true;
18773        self.active_indent_guides_state.dirty = true;
18774    }
18775
18776    pub fn update_renderer_widths(
18777        &mut self,
18778        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18779        cx: &mut Context<Self>,
18780    ) -> bool {
18781        self.display_map
18782            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18783    }
18784
18785    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18786        self.display_map.read(cx).fold_placeholder.clone()
18787    }
18788
18789    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18790        self.buffer.update(cx, |buffer, cx| {
18791            buffer.set_all_diff_hunks_expanded(cx);
18792        });
18793    }
18794
18795    pub fn expand_all_diff_hunks(
18796        &mut self,
18797        _: &ExpandAllDiffHunks,
18798        _window: &mut Window,
18799        cx: &mut Context<Self>,
18800    ) {
18801        self.buffer.update(cx, |buffer, cx| {
18802            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18803        });
18804    }
18805
18806    pub fn collapse_all_diff_hunks(
18807        &mut self,
18808        _: &CollapseAllDiffHunks,
18809        _window: &mut Window,
18810        cx: &mut Context<Self>,
18811    ) {
18812        self.buffer.update(cx, |buffer, cx| {
18813            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18814        });
18815    }
18816
18817    pub fn toggle_selected_diff_hunks(
18818        &mut self,
18819        _: &ToggleSelectedDiffHunks,
18820        _window: &mut Window,
18821        cx: &mut Context<Self>,
18822    ) {
18823        let ranges: Vec<_> = self
18824            .selections
18825            .disjoint_anchors()
18826            .iter()
18827            .map(|s| s.range())
18828            .collect();
18829        self.toggle_diff_hunks_in_ranges(ranges, cx);
18830    }
18831
18832    pub fn diff_hunks_in_ranges<'a>(
18833        &'a self,
18834        ranges: &'a [Range<Anchor>],
18835        buffer: &'a MultiBufferSnapshot,
18836    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18837        ranges.iter().flat_map(move |range| {
18838            let end_excerpt_id = range.end.excerpt_id;
18839            let range = range.to_point(buffer);
18840            let mut peek_end = range.end;
18841            if range.end.row < buffer.max_row().0 {
18842                peek_end = Point::new(range.end.row + 1, 0);
18843            }
18844            buffer
18845                .diff_hunks_in_range(range.start..peek_end)
18846                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18847        })
18848    }
18849
18850    pub fn has_stageable_diff_hunks_in_ranges(
18851        &self,
18852        ranges: &[Range<Anchor>],
18853        snapshot: &MultiBufferSnapshot,
18854    ) -> bool {
18855        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18856        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18857    }
18858
18859    pub fn toggle_staged_selected_diff_hunks(
18860        &mut self,
18861        _: &::git::ToggleStaged,
18862        _: &mut Window,
18863        cx: &mut Context<Self>,
18864    ) {
18865        let snapshot = self.buffer.read(cx).snapshot(cx);
18866        let ranges: Vec<_> = self
18867            .selections
18868            .disjoint_anchors()
18869            .iter()
18870            .map(|s| s.range())
18871            .collect();
18872        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18873        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18874    }
18875
18876    pub fn set_render_diff_hunk_controls(
18877        &mut self,
18878        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18879        cx: &mut Context<Self>,
18880    ) {
18881        self.render_diff_hunk_controls = render_diff_hunk_controls;
18882        cx.notify();
18883    }
18884
18885    pub fn stage_and_next(
18886        &mut self,
18887        _: &::git::StageAndNext,
18888        window: &mut Window,
18889        cx: &mut Context<Self>,
18890    ) {
18891        self.do_stage_or_unstage_and_next(true, window, cx);
18892    }
18893
18894    pub fn unstage_and_next(
18895        &mut self,
18896        _: &::git::UnstageAndNext,
18897        window: &mut Window,
18898        cx: &mut Context<Self>,
18899    ) {
18900        self.do_stage_or_unstage_and_next(false, window, cx);
18901    }
18902
18903    pub fn stage_or_unstage_diff_hunks(
18904        &mut self,
18905        stage: bool,
18906        ranges: Vec<Range<Anchor>>,
18907        cx: &mut Context<Self>,
18908    ) {
18909        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18910        cx.spawn(async move |this, cx| {
18911            task.await?;
18912            this.update(cx, |this, cx| {
18913                let snapshot = this.buffer.read(cx).snapshot(cx);
18914                let chunk_by = this
18915                    .diff_hunks_in_ranges(&ranges, &snapshot)
18916                    .chunk_by(|hunk| hunk.buffer_id);
18917                for (buffer_id, hunks) in &chunk_by {
18918                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18919                }
18920            })
18921        })
18922        .detach_and_log_err(cx);
18923    }
18924
18925    fn save_buffers_for_ranges_if_needed(
18926        &mut self,
18927        ranges: &[Range<Anchor>],
18928        cx: &mut Context<Editor>,
18929    ) -> Task<Result<()>> {
18930        let multibuffer = self.buffer.read(cx);
18931        let snapshot = multibuffer.read(cx);
18932        let buffer_ids: HashSet<_> = ranges
18933            .iter()
18934            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18935            .collect();
18936        drop(snapshot);
18937
18938        let mut buffers = HashSet::default();
18939        for buffer_id in buffer_ids {
18940            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18941                let buffer = buffer_entity.read(cx);
18942                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18943                {
18944                    buffers.insert(buffer_entity);
18945                }
18946            }
18947        }
18948
18949        if let Some(project) = &self.project {
18950            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18951        } else {
18952            Task::ready(Ok(()))
18953        }
18954    }
18955
18956    fn do_stage_or_unstage_and_next(
18957        &mut self,
18958        stage: bool,
18959        window: &mut Window,
18960        cx: &mut Context<Self>,
18961    ) {
18962        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18963
18964        if ranges.iter().any(|range| range.start != range.end) {
18965            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18966            return;
18967        }
18968
18969        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18970        let snapshot = self.snapshot(window, cx);
18971        let position = self
18972            .selections
18973            .newest::<Point>(&snapshot.display_snapshot)
18974            .head();
18975        let mut row = snapshot
18976            .buffer_snapshot()
18977            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18978            .find(|hunk| hunk.row_range.start.0 > position.row)
18979            .map(|hunk| hunk.row_range.start);
18980
18981        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18982        // Outside of the project diff editor, wrap around to the beginning.
18983        if !all_diff_hunks_expanded {
18984            row = row.or_else(|| {
18985                snapshot
18986                    .buffer_snapshot()
18987                    .diff_hunks_in_range(Point::zero()..position)
18988                    .find(|hunk| hunk.row_range.end.0 < position.row)
18989                    .map(|hunk| hunk.row_range.start)
18990            });
18991        }
18992
18993        if let Some(row) = row {
18994            let destination = Point::new(row.0, 0);
18995            let autoscroll = Autoscroll::center();
18996
18997            self.unfold_ranges(&[destination..destination], false, false, cx);
18998            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18999                s.select_ranges([destination..destination]);
19000            });
19001        }
19002    }
19003
19004    fn do_stage_or_unstage(
19005        &self,
19006        stage: bool,
19007        buffer_id: BufferId,
19008        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19009        cx: &mut App,
19010    ) -> Option<()> {
19011        let project = self.project()?;
19012        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19013        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19014        let buffer_snapshot = buffer.read(cx).snapshot();
19015        let file_exists = buffer_snapshot
19016            .file()
19017            .is_some_and(|file| file.disk_state().exists());
19018        diff.update(cx, |diff, cx| {
19019            diff.stage_or_unstage_hunks(
19020                stage,
19021                &hunks
19022                    .map(|hunk| buffer_diff::DiffHunk {
19023                        buffer_range: hunk.buffer_range,
19024                        diff_base_byte_range: hunk.diff_base_byte_range,
19025                        secondary_status: hunk.secondary_status,
19026                        range: Point::zero()..Point::zero(), // unused
19027                    })
19028                    .collect::<Vec<_>>(),
19029                &buffer_snapshot,
19030                file_exists,
19031                cx,
19032            )
19033        });
19034        None
19035    }
19036
19037    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19038        let ranges: Vec<_> = self
19039            .selections
19040            .disjoint_anchors()
19041            .iter()
19042            .map(|s| s.range())
19043            .collect();
19044        self.buffer
19045            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19046    }
19047
19048    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19049        self.buffer.update(cx, |buffer, cx| {
19050            let ranges = vec![Anchor::min()..Anchor::max()];
19051            if !buffer.all_diff_hunks_expanded()
19052                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19053            {
19054                buffer.collapse_diff_hunks(ranges, cx);
19055                true
19056            } else {
19057                false
19058            }
19059        })
19060    }
19061
19062    fn toggle_diff_hunks_in_ranges(
19063        &mut self,
19064        ranges: Vec<Range<Anchor>>,
19065        cx: &mut Context<Editor>,
19066    ) {
19067        self.buffer.update(cx, |buffer, cx| {
19068            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19069            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19070        })
19071    }
19072
19073    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19074        self.buffer.update(cx, |buffer, cx| {
19075            let snapshot = buffer.snapshot(cx);
19076            let excerpt_id = range.end.excerpt_id;
19077            let point_range = range.to_point(&snapshot);
19078            let expand = !buffer.single_hunk_is_expanded(range, cx);
19079            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19080        })
19081    }
19082
19083    pub(crate) fn apply_all_diff_hunks(
19084        &mut self,
19085        _: &ApplyAllDiffHunks,
19086        window: &mut Window,
19087        cx: &mut Context<Self>,
19088    ) {
19089        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19090
19091        let buffers = self.buffer.read(cx).all_buffers();
19092        for branch_buffer in buffers {
19093            branch_buffer.update(cx, |branch_buffer, cx| {
19094                branch_buffer.merge_into_base(Vec::new(), cx);
19095            });
19096        }
19097
19098        if let Some(project) = self.project.clone() {
19099            self.save(
19100                SaveOptions {
19101                    format: true,
19102                    autosave: false,
19103                },
19104                project,
19105                window,
19106                cx,
19107            )
19108            .detach_and_log_err(cx);
19109        }
19110    }
19111
19112    pub(crate) fn apply_selected_diff_hunks(
19113        &mut self,
19114        _: &ApplyDiffHunk,
19115        window: &mut Window,
19116        cx: &mut Context<Self>,
19117    ) {
19118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19119        let snapshot = self.snapshot(window, cx);
19120        let hunks = snapshot.hunks_for_ranges(
19121            self.selections
19122                .all(&snapshot.display_snapshot)
19123                .into_iter()
19124                .map(|selection| selection.range()),
19125        );
19126        let mut ranges_by_buffer = HashMap::default();
19127        self.transact(window, cx, |editor, _window, cx| {
19128            for hunk in hunks {
19129                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19130                    ranges_by_buffer
19131                        .entry(buffer.clone())
19132                        .or_insert_with(Vec::new)
19133                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19134                }
19135            }
19136
19137            for (buffer, ranges) in ranges_by_buffer {
19138                buffer.update(cx, |buffer, cx| {
19139                    buffer.merge_into_base(ranges, cx);
19140                });
19141            }
19142        });
19143
19144        if let Some(project) = self.project.clone() {
19145            self.save(
19146                SaveOptions {
19147                    format: true,
19148                    autosave: false,
19149                },
19150                project,
19151                window,
19152                cx,
19153            )
19154            .detach_and_log_err(cx);
19155        }
19156    }
19157
19158    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19159        if hovered != self.gutter_hovered {
19160            self.gutter_hovered = hovered;
19161            cx.notify();
19162        }
19163    }
19164
19165    pub fn insert_blocks(
19166        &mut self,
19167        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19168        autoscroll: Option<Autoscroll>,
19169        cx: &mut Context<Self>,
19170    ) -> Vec<CustomBlockId> {
19171        let blocks = self
19172            .display_map
19173            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19174        if let Some(autoscroll) = autoscroll {
19175            self.request_autoscroll(autoscroll, cx);
19176        }
19177        cx.notify();
19178        blocks
19179    }
19180
19181    pub fn resize_blocks(
19182        &mut self,
19183        heights: HashMap<CustomBlockId, u32>,
19184        autoscroll: Option<Autoscroll>,
19185        cx: &mut Context<Self>,
19186    ) {
19187        self.display_map
19188            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19189        if let Some(autoscroll) = autoscroll {
19190            self.request_autoscroll(autoscroll, cx);
19191        }
19192        cx.notify();
19193    }
19194
19195    pub fn replace_blocks(
19196        &mut self,
19197        renderers: HashMap<CustomBlockId, RenderBlock>,
19198        autoscroll: Option<Autoscroll>,
19199        cx: &mut Context<Self>,
19200    ) {
19201        self.display_map
19202            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19203        if let Some(autoscroll) = autoscroll {
19204            self.request_autoscroll(autoscroll, cx);
19205        }
19206        cx.notify();
19207    }
19208
19209    pub fn remove_blocks(
19210        &mut self,
19211        block_ids: HashSet<CustomBlockId>,
19212        autoscroll: Option<Autoscroll>,
19213        cx: &mut Context<Self>,
19214    ) {
19215        self.display_map.update(cx, |display_map, cx| {
19216            display_map.remove_blocks(block_ids, cx)
19217        });
19218        if let Some(autoscroll) = autoscroll {
19219            self.request_autoscroll(autoscroll, cx);
19220        }
19221        cx.notify();
19222    }
19223
19224    pub fn row_for_block(
19225        &self,
19226        block_id: CustomBlockId,
19227        cx: &mut Context<Self>,
19228    ) -> Option<DisplayRow> {
19229        self.display_map
19230            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19231    }
19232
19233    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19234        self.focused_block = Some(focused_block);
19235    }
19236
19237    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19238        self.focused_block.take()
19239    }
19240
19241    pub fn insert_creases(
19242        &mut self,
19243        creases: impl IntoIterator<Item = Crease<Anchor>>,
19244        cx: &mut Context<Self>,
19245    ) -> Vec<CreaseId> {
19246        self.display_map
19247            .update(cx, |map, cx| map.insert_creases(creases, cx))
19248    }
19249
19250    pub fn remove_creases(
19251        &mut self,
19252        ids: impl IntoIterator<Item = CreaseId>,
19253        cx: &mut Context<Self>,
19254    ) -> Vec<(CreaseId, Range<Anchor>)> {
19255        self.display_map
19256            .update(cx, |map, cx| map.remove_creases(ids, cx))
19257    }
19258
19259    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19260        self.display_map
19261            .update(cx, |map, cx| map.snapshot(cx))
19262            .longest_row()
19263    }
19264
19265    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19266        self.display_map
19267            .update(cx, |map, cx| map.snapshot(cx))
19268            .max_point()
19269    }
19270
19271    pub fn text(&self, cx: &App) -> String {
19272        self.buffer.read(cx).read(cx).text()
19273    }
19274
19275    pub fn is_empty(&self, cx: &App) -> bool {
19276        self.buffer.read(cx).read(cx).is_empty()
19277    }
19278
19279    pub fn text_option(&self, cx: &App) -> Option<String> {
19280        let text = self.text(cx);
19281        let text = text.trim();
19282
19283        if text.is_empty() {
19284            return None;
19285        }
19286
19287        Some(text.to_string())
19288    }
19289
19290    pub fn set_text(
19291        &mut self,
19292        text: impl Into<Arc<str>>,
19293        window: &mut Window,
19294        cx: &mut Context<Self>,
19295    ) {
19296        self.transact(window, cx, |this, _, cx| {
19297            this.buffer
19298                .read(cx)
19299                .as_singleton()
19300                .expect("you can only call set_text on editors for singleton buffers")
19301                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19302        });
19303    }
19304
19305    pub fn display_text(&self, cx: &mut App) -> String {
19306        self.display_map
19307            .update(cx, |map, cx| map.snapshot(cx))
19308            .text()
19309    }
19310
19311    fn create_minimap(
19312        &self,
19313        minimap_settings: MinimapSettings,
19314        window: &mut Window,
19315        cx: &mut Context<Self>,
19316    ) -> Option<Entity<Self>> {
19317        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19318            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19319    }
19320
19321    fn initialize_new_minimap(
19322        &self,
19323        minimap_settings: MinimapSettings,
19324        window: &mut Window,
19325        cx: &mut Context<Self>,
19326    ) -> Entity<Self> {
19327        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19328
19329        let mut minimap = Editor::new_internal(
19330            EditorMode::Minimap {
19331                parent: cx.weak_entity(),
19332            },
19333            self.buffer.clone(),
19334            None,
19335            Some(self.display_map.clone()),
19336            window,
19337            cx,
19338        );
19339        minimap.scroll_manager.clone_state(&self.scroll_manager);
19340        minimap.set_text_style_refinement(TextStyleRefinement {
19341            font_size: Some(MINIMAP_FONT_SIZE),
19342            font_weight: Some(MINIMAP_FONT_WEIGHT),
19343            ..Default::default()
19344        });
19345        minimap.update_minimap_configuration(minimap_settings, cx);
19346        cx.new(|_| minimap)
19347    }
19348
19349    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19350        let current_line_highlight = minimap_settings
19351            .current_line_highlight
19352            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19353        self.set_current_line_highlight(Some(current_line_highlight));
19354    }
19355
19356    pub fn minimap(&self) -> Option<&Entity<Self>> {
19357        self.minimap
19358            .as_ref()
19359            .filter(|_| self.minimap_visibility.visible())
19360    }
19361
19362    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19363        let mut wrap_guides = smallvec![];
19364
19365        if self.show_wrap_guides == Some(false) {
19366            return wrap_guides;
19367        }
19368
19369        let settings = self.buffer.read(cx).language_settings(cx);
19370        if settings.show_wrap_guides {
19371            match self.soft_wrap_mode(cx) {
19372                SoftWrap::Column(soft_wrap) => {
19373                    wrap_guides.push((soft_wrap as usize, true));
19374                }
19375                SoftWrap::Bounded(soft_wrap) => {
19376                    wrap_guides.push((soft_wrap as usize, true));
19377                }
19378                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19379            }
19380            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19381        }
19382
19383        wrap_guides
19384    }
19385
19386    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19387        let settings = self.buffer.read(cx).language_settings(cx);
19388        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19389        match mode {
19390            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19391                SoftWrap::None
19392            }
19393            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19394            language_settings::SoftWrap::PreferredLineLength => {
19395                SoftWrap::Column(settings.preferred_line_length)
19396            }
19397            language_settings::SoftWrap::Bounded => {
19398                SoftWrap::Bounded(settings.preferred_line_length)
19399            }
19400        }
19401    }
19402
19403    pub fn set_soft_wrap_mode(
19404        &mut self,
19405        mode: language_settings::SoftWrap,
19406
19407        cx: &mut Context<Self>,
19408    ) {
19409        self.soft_wrap_mode_override = Some(mode);
19410        cx.notify();
19411    }
19412
19413    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19414        self.hard_wrap = hard_wrap;
19415        cx.notify();
19416    }
19417
19418    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19419        self.text_style_refinement = Some(style);
19420    }
19421
19422    /// called by the Element so we know what style we were most recently rendered with.
19423    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19424        // We intentionally do not inform the display map about the minimap style
19425        // so that wrapping is not recalculated and stays consistent for the editor
19426        // and its linked minimap.
19427        if !self.mode.is_minimap() {
19428            let font = style.text.font();
19429            let font_size = style.text.font_size.to_pixels(window.rem_size());
19430            let display_map = self
19431                .placeholder_display_map
19432                .as_ref()
19433                .filter(|_| self.is_empty(cx))
19434                .unwrap_or(&self.display_map);
19435
19436            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19437        }
19438        self.style = Some(style);
19439    }
19440
19441    pub fn style(&self) -> Option<&EditorStyle> {
19442        self.style.as_ref()
19443    }
19444
19445    // Called by the element. This method is not designed to be called outside of the editor
19446    // element's layout code because it does not notify when rewrapping is computed synchronously.
19447    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19448        if self.is_empty(cx) {
19449            self.placeholder_display_map
19450                .as_ref()
19451                .map_or(false, |display_map| {
19452                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19453                })
19454        } else {
19455            self.display_map
19456                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19457        }
19458    }
19459
19460    pub fn set_soft_wrap(&mut self) {
19461        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19462    }
19463
19464    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19465        if self.soft_wrap_mode_override.is_some() {
19466            self.soft_wrap_mode_override.take();
19467        } else {
19468            let soft_wrap = match self.soft_wrap_mode(cx) {
19469                SoftWrap::GitDiff => return,
19470                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19471                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19472                    language_settings::SoftWrap::None
19473                }
19474            };
19475            self.soft_wrap_mode_override = Some(soft_wrap);
19476        }
19477        cx.notify();
19478    }
19479
19480    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19481        let Some(workspace) = self.workspace() else {
19482            return;
19483        };
19484        let fs = workspace.read(cx).app_state().fs.clone();
19485        let current_show = TabBarSettings::get_global(cx).show;
19486        update_settings_file(fs, cx, move |setting, _| {
19487            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19488        });
19489    }
19490
19491    pub fn toggle_indent_guides(
19492        &mut self,
19493        _: &ToggleIndentGuides,
19494        _: &mut Window,
19495        cx: &mut Context<Self>,
19496    ) {
19497        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19498            self.buffer
19499                .read(cx)
19500                .language_settings(cx)
19501                .indent_guides
19502                .enabled
19503        });
19504        self.show_indent_guides = Some(!currently_enabled);
19505        cx.notify();
19506    }
19507
19508    fn should_show_indent_guides(&self) -> Option<bool> {
19509        self.show_indent_guides
19510    }
19511
19512    pub fn toggle_line_numbers(
19513        &mut self,
19514        _: &ToggleLineNumbers,
19515        _: &mut Window,
19516        cx: &mut Context<Self>,
19517    ) {
19518        let mut editor_settings = EditorSettings::get_global(cx).clone();
19519        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19520        EditorSettings::override_global(editor_settings, cx);
19521    }
19522
19523    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19524        if let Some(show_line_numbers) = self.show_line_numbers {
19525            return show_line_numbers;
19526        }
19527        EditorSettings::get_global(cx).gutter.line_numbers
19528    }
19529
19530    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19531        self.use_relative_line_numbers
19532            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19533    }
19534
19535    pub fn toggle_relative_line_numbers(
19536        &mut self,
19537        _: &ToggleRelativeLineNumbers,
19538        _: &mut Window,
19539        cx: &mut Context<Self>,
19540    ) {
19541        let is_relative = self.should_use_relative_line_numbers(cx);
19542        self.set_relative_line_number(Some(!is_relative), cx)
19543    }
19544
19545    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19546        self.use_relative_line_numbers = is_relative;
19547        cx.notify();
19548    }
19549
19550    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19551        self.show_gutter = show_gutter;
19552        cx.notify();
19553    }
19554
19555    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19556        self.show_scrollbars = ScrollbarAxes {
19557            horizontal: show,
19558            vertical: show,
19559        };
19560        cx.notify();
19561    }
19562
19563    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19564        self.show_scrollbars.vertical = show;
19565        cx.notify();
19566    }
19567
19568    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19569        self.show_scrollbars.horizontal = show;
19570        cx.notify();
19571    }
19572
19573    pub fn set_minimap_visibility(
19574        &mut self,
19575        minimap_visibility: MinimapVisibility,
19576        window: &mut Window,
19577        cx: &mut Context<Self>,
19578    ) {
19579        if self.minimap_visibility != minimap_visibility {
19580            if minimap_visibility.visible() && self.minimap.is_none() {
19581                let minimap_settings = EditorSettings::get_global(cx).minimap;
19582                self.minimap =
19583                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19584            }
19585            self.minimap_visibility = minimap_visibility;
19586            cx.notify();
19587        }
19588    }
19589
19590    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19591        self.set_show_scrollbars(false, cx);
19592        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19593    }
19594
19595    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19596        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19597    }
19598
19599    /// Normally the text in full mode and auto height editors is padded on the
19600    /// left side by roughly half a character width for improved hit testing.
19601    ///
19602    /// Use this method to disable this for cases where this is not wanted (e.g.
19603    /// if you want to align the editor text with some other text above or below)
19604    /// or if you want to add this padding to single-line editors.
19605    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19606        self.offset_content = offset_content;
19607        cx.notify();
19608    }
19609
19610    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19611        self.show_line_numbers = Some(show_line_numbers);
19612        cx.notify();
19613    }
19614
19615    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19616        self.disable_expand_excerpt_buttons = true;
19617        cx.notify();
19618    }
19619
19620    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19621        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19622        cx.notify();
19623    }
19624
19625    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19626        self.show_code_actions = Some(show_code_actions);
19627        cx.notify();
19628    }
19629
19630    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19631        self.show_runnables = Some(show_runnables);
19632        cx.notify();
19633    }
19634
19635    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19636        self.show_breakpoints = Some(show_breakpoints);
19637        cx.notify();
19638    }
19639
19640    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19641        if self.display_map.read(cx).masked != masked {
19642            self.display_map.update(cx, |map, _| map.masked = masked);
19643        }
19644        cx.notify()
19645    }
19646
19647    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19648        self.show_wrap_guides = Some(show_wrap_guides);
19649        cx.notify();
19650    }
19651
19652    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19653        self.show_indent_guides = Some(show_indent_guides);
19654        cx.notify();
19655    }
19656
19657    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19658        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19659            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19660                && let Some(dir) = file.abs_path(cx).parent()
19661            {
19662                return Some(dir.to_owned());
19663            }
19664        }
19665
19666        None
19667    }
19668
19669    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19670        self.active_excerpt(cx)?
19671            .1
19672            .read(cx)
19673            .file()
19674            .and_then(|f| f.as_local())
19675    }
19676
19677    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19678        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19679            let buffer = buffer.read(cx);
19680            if let Some(project_path) = buffer.project_path(cx) {
19681                let project = self.project()?.read(cx);
19682                project.absolute_path(&project_path, cx)
19683            } else {
19684                buffer
19685                    .file()
19686                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19687            }
19688        })
19689    }
19690
19691    pub fn reveal_in_finder(
19692        &mut self,
19693        _: &RevealInFileManager,
19694        _window: &mut Window,
19695        cx: &mut Context<Self>,
19696    ) {
19697        if let Some(target) = self.target_file(cx) {
19698            cx.reveal_path(&target.abs_path(cx));
19699        }
19700    }
19701
19702    pub fn copy_path(
19703        &mut self,
19704        _: &zed_actions::workspace::CopyPath,
19705        _window: &mut Window,
19706        cx: &mut Context<Self>,
19707    ) {
19708        if let Some(path) = self.target_file_abs_path(cx)
19709            && let Some(path) = path.to_str()
19710        {
19711            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19712        } else {
19713            cx.propagate();
19714        }
19715    }
19716
19717    pub fn copy_relative_path(
19718        &mut self,
19719        _: &zed_actions::workspace::CopyRelativePath,
19720        _window: &mut Window,
19721        cx: &mut Context<Self>,
19722    ) {
19723        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19724            let project = self.project()?.read(cx);
19725            let path = buffer.read(cx).file()?.path();
19726            let path = path.display(project.path_style(cx));
19727            Some(path)
19728        }) {
19729            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19730        } else {
19731            cx.propagate();
19732        }
19733    }
19734
19735    /// Returns the project path for the editor's buffer, if any buffer is
19736    /// opened in the editor.
19737    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19738        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19739            buffer.read(cx).project_path(cx)
19740        } else {
19741            None
19742        }
19743    }
19744
19745    // Returns true if the editor handled a go-to-line request
19746    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19747        maybe!({
19748            let breakpoint_store = self.breakpoint_store.as_ref()?;
19749
19750            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19751            else {
19752                self.clear_row_highlights::<ActiveDebugLine>();
19753                return None;
19754            };
19755
19756            let position = active_stack_frame.position;
19757            let buffer_id = position.buffer_id?;
19758            let snapshot = self
19759                .project
19760                .as_ref()?
19761                .read(cx)
19762                .buffer_for_id(buffer_id, cx)?
19763                .read(cx)
19764                .snapshot();
19765
19766            let mut handled = false;
19767            for (id, ExcerptRange { context, .. }) in
19768                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19769            {
19770                if context.start.cmp(&position, &snapshot).is_ge()
19771                    || context.end.cmp(&position, &snapshot).is_lt()
19772                {
19773                    continue;
19774                }
19775                let snapshot = self.buffer.read(cx).snapshot(cx);
19776                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19777
19778                handled = true;
19779                self.clear_row_highlights::<ActiveDebugLine>();
19780
19781                self.go_to_line::<ActiveDebugLine>(
19782                    multibuffer_anchor,
19783                    Some(cx.theme().colors().editor_debugger_active_line_background),
19784                    window,
19785                    cx,
19786                );
19787
19788                cx.notify();
19789            }
19790
19791            handled.then_some(())
19792        })
19793        .is_some()
19794    }
19795
19796    pub fn copy_file_name_without_extension(
19797        &mut self,
19798        _: &CopyFileNameWithoutExtension,
19799        _: &mut Window,
19800        cx: &mut Context<Self>,
19801    ) {
19802        if let Some(file) = self.target_file(cx)
19803            && let Some(file_stem) = file.path().file_stem()
19804        {
19805            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19806        }
19807    }
19808
19809    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19810        if let Some(file) = self.target_file(cx)
19811            && let Some(name) = file.path().file_name()
19812        {
19813            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19814        }
19815    }
19816
19817    pub fn toggle_git_blame(
19818        &mut self,
19819        _: &::git::Blame,
19820        window: &mut Window,
19821        cx: &mut Context<Self>,
19822    ) {
19823        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19824
19825        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19826            self.start_git_blame(true, window, cx);
19827        }
19828
19829        cx.notify();
19830    }
19831
19832    pub fn toggle_git_blame_inline(
19833        &mut self,
19834        _: &ToggleGitBlameInline,
19835        window: &mut Window,
19836        cx: &mut Context<Self>,
19837    ) {
19838        self.toggle_git_blame_inline_internal(true, window, cx);
19839        cx.notify();
19840    }
19841
19842    pub fn open_git_blame_commit(
19843        &mut self,
19844        _: &OpenGitBlameCommit,
19845        window: &mut Window,
19846        cx: &mut Context<Self>,
19847    ) {
19848        self.open_git_blame_commit_internal(window, cx);
19849    }
19850
19851    fn open_git_blame_commit_internal(
19852        &mut self,
19853        window: &mut Window,
19854        cx: &mut Context<Self>,
19855    ) -> Option<()> {
19856        let blame = self.blame.as_ref()?;
19857        let snapshot = self.snapshot(window, cx);
19858        let cursor = self
19859            .selections
19860            .newest::<Point>(&snapshot.display_snapshot)
19861            .head();
19862        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19863        let (_, blame_entry) = blame
19864            .update(cx, |blame, cx| {
19865                blame
19866                    .blame_for_rows(
19867                        &[RowInfo {
19868                            buffer_id: Some(buffer.remote_id()),
19869                            buffer_row: Some(point.row),
19870                            ..Default::default()
19871                        }],
19872                        cx,
19873                    )
19874                    .next()
19875            })
19876            .flatten()?;
19877        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19878        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19879        let workspace = self.workspace()?.downgrade();
19880        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19881        None
19882    }
19883
19884    pub fn git_blame_inline_enabled(&self) -> bool {
19885        self.git_blame_inline_enabled
19886    }
19887
19888    pub fn toggle_selection_menu(
19889        &mut self,
19890        _: &ToggleSelectionMenu,
19891        _: &mut Window,
19892        cx: &mut Context<Self>,
19893    ) {
19894        self.show_selection_menu = self
19895            .show_selection_menu
19896            .map(|show_selections_menu| !show_selections_menu)
19897            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19898
19899        cx.notify();
19900    }
19901
19902    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19903        self.show_selection_menu
19904            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19905    }
19906
19907    fn start_git_blame(
19908        &mut self,
19909        user_triggered: bool,
19910        window: &mut Window,
19911        cx: &mut Context<Self>,
19912    ) {
19913        if let Some(project) = self.project() {
19914            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19915                && buffer.read(cx).file().is_none()
19916            {
19917                return;
19918            }
19919
19920            let focused = self.focus_handle(cx).contains_focused(window, cx);
19921
19922            let project = project.clone();
19923            let blame = cx
19924                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19925            self.blame_subscription =
19926                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19927            self.blame = Some(blame);
19928        }
19929    }
19930
19931    fn toggle_git_blame_inline_internal(
19932        &mut self,
19933        user_triggered: bool,
19934        window: &mut Window,
19935        cx: &mut Context<Self>,
19936    ) {
19937        if self.git_blame_inline_enabled {
19938            self.git_blame_inline_enabled = false;
19939            self.show_git_blame_inline = false;
19940            self.show_git_blame_inline_delay_task.take();
19941        } else {
19942            self.git_blame_inline_enabled = true;
19943            self.start_git_blame_inline(user_triggered, window, cx);
19944        }
19945
19946        cx.notify();
19947    }
19948
19949    fn start_git_blame_inline(
19950        &mut self,
19951        user_triggered: bool,
19952        window: &mut Window,
19953        cx: &mut Context<Self>,
19954    ) {
19955        self.start_git_blame(user_triggered, window, cx);
19956
19957        if ProjectSettings::get_global(cx)
19958            .git
19959            .inline_blame_delay()
19960            .is_some()
19961        {
19962            self.start_inline_blame_timer(window, cx);
19963        } else {
19964            self.show_git_blame_inline = true
19965        }
19966    }
19967
19968    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19969        self.blame.as_ref()
19970    }
19971
19972    pub fn show_git_blame_gutter(&self) -> bool {
19973        self.show_git_blame_gutter
19974    }
19975
19976    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19977        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19978    }
19979
19980    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19981        self.show_git_blame_inline
19982            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19983            && !self.newest_selection_head_on_empty_line(cx)
19984            && self.has_blame_entries(cx)
19985    }
19986
19987    fn has_blame_entries(&self, cx: &App) -> bool {
19988        self.blame()
19989            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19990    }
19991
19992    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19993        let cursor_anchor = self.selections.newest_anchor().head();
19994
19995        let snapshot = self.buffer.read(cx).snapshot(cx);
19996        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19997
19998        snapshot.line_len(buffer_row) == 0
19999    }
20000
20001    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20002        let buffer_and_selection = maybe!({
20003            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20004            let selection_range = selection.range();
20005
20006            let multi_buffer = self.buffer().read(cx);
20007            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20008            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20009
20010            let (buffer, range, _) = if selection.reversed {
20011                buffer_ranges.first()
20012            } else {
20013                buffer_ranges.last()
20014            }?;
20015
20016            let selection = text::ToPoint::to_point(&range.start, buffer).row
20017                ..text::ToPoint::to_point(&range.end, buffer).row;
20018            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20019        });
20020
20021        let Some((buffer, selection)) = buffer_and_selection else {
20022            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20023        };
20024
20025        let Some(project) = self.project() else {
20026            return Task::ready(Err(anyhow!("editor does not have project")));
20027        };
20028
20029        project.update(cx, |project, cx| {
20030            project.get_permalink_to_line(&buffer, selection, cx)
20031        })
20032    }
20033
20034    pub fn copy_permalink_to_line(
20035        &mut self,
20036        _: &CopyPermalinkToLine,
20037        window: &mut Window,
20038        cx: &mut Context<Self>,
20039    ) {
20040        let permalink_task = self.get_permalink_to_line(cx);
20041        let workspace = self.workspace();
20042
20043        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20044            Ok(permalink) => {
20045                cx.update(|_, cx| {
20046                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20047                })
20048                .ok();
20049            }
20050            Err(err) => {
20051                let message = format!("Failed to copy permalink: {err}");
20052
20053                anyhow::Result::<()>::Err(err).log_err();
20054
20055                if let Some(workspace) = workspace {
20056                    workspace
20057                        .update_in(cx, |workspace, _, cx| {
20058                            struct CopyPermalinkToLine;
20059
20060                            workspace.show_toast(
20061                                Toast::new(
20062                                    NotificationId::unique::<CopyPermalinkToLine>(),
20063                                    message,
20064                                ),
20065                                cx,
20066                            )
20067                        })
20068                        .ok();
20069                }
20070            }
20071        })
20072        .detach();
20073    }
20074
20075    pub fn copy_file_location(
20076        &mut self,
20077        _: &CopyFileLocation,
20078        _: &mut Window,
20079        cx: &mut Context<Self>,
20080    ) {
20081        let selection = self
20082            .selections
20083            .newest::<Point>(&self.display_snapshot(cx))
20084            .start
20085            .row
20086            + 1;
20087        if let Some(file) = self.target_file(cx) {
20088            let path = file.path().display(file.path_style(cx));
20089            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20090        }
20091    }
20092
20093    pub fn open_permalink_to_line(
20094        &mut self,
20095        _: &OpenPermalinkToLine,
20096        window: &mut Window,
20097        cx: &mut Context<Self>,
20098    ) {
20099        let permalink_task = self.get_permalink_to_line(cx);
20100        let workspace = self.workspace();
20101
20102        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20103            Ok(permalink) => {
20104                cx.update(|_, cx| {
20105                    cx.open_url(permalink.as_ref());
20106                })
20107                .ok();
20108            }
20109            Err(err) => {
20110                let message = format!("Failed to open permalink: {err}");
20111
20112                anyhow::Result::<()>::Err(err).log_err();
20113
20114                if let Some(workspace) = workspace {
20115                    workspace
20116                        .update(cx, |workspace, cx| {
20117                            struct OpenPermalinkToLine;
20118
20119                            workspace.show_toast(
20120                                Toast::new(
20121                                    NotificationId::unique::<OpenPermalinkToLine>(),
20122                                    message,
20123                                ),
20124                                cx,
20125                            )
20126                        })
20127                        .ok();
20128                }
20129            }
20130        })
20131        .detach();
20132    }
20133
20134    pub fn insert_uuid_v4(
20135        &mut self,
20136        _: &InsertUuidV4,
20137        window: &mut Window,
20138        cx: &mut Context<Self>,
20139    ) {
20140        self.insert_uuid(UuidVersion::V4, window, cx);
20141    }
20142
20143    pub fn insert_uuid_v7(
20144        &mut self,
20145        _: &InsertUuidV7,
20146        window: &mut Window,
20147        cx: &mut Context<Self>,
20148    ) {
20149        self.insert_uuid(UuidVersion::V7, window, cx);
20150    }
20151
20152    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20153        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20154        self.transact(window, cx, |this, window, cx| {
20155            let edits = this
20156                .selections
20157                .all::<Point>(&this.display_snapshot(cx))
20158                .into_iter()
20159                .map(|selection| {
20160                    let uuid = match version {
20161                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20162                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20163                    };
20164
20165                    (selection.range(), uuid.to_string())
20166                });
20167            this.edit(edits, cx);
20168            this.refresh_edit_prediction(true, false, window, cx);
20169        });
20170    }
20171
20172    pub fn open_selections_in_multibuffer(
20173        &mut self,
20174        _: &OpenSelectionsInMultibuffer,
20175        window: &mut Window,
20176        cx: &mut Context<Self>,
20177    ) {
20178        let multibuffer = self.buffer.read(cx);
20179
20180        let Some(buffer) = multibuffer.as_singleton() else {
20181            return;
20182        };
20183
20184        let Some(workspace) = self.workspace() else {
20185            return;
20186        };
20187
20188        let title = multibuffer.title(cx).to_string();
20189
20190        let locations = self
20191            .selections
20192            .all_anchors(cx)
20193            .iter()
20194            .map(|selection| {
20195                (
20196                    buffer.clone(),
20197                    (selection.start.text_anchor..selection.end.text_anchor)
20198                        .to_point(buffer.read(cx)),
20199                )
20200            })
20201            .into_group_map();
20202
20203        cx.spawn_in(window, async move |_, cx| {
20204            workspace.update_in(cx, |workspace, window, cx| {
20205                Self::open_locations_in_multibuffer(
20206                    workspace,
20207                    locations,
20208                    format!("Selections for '{title}'"),
20209                    false,
20210                    MultibufferSelectionMode::All,
20211                    window,
20212                    cx,
20213                );
20214            })
20215        })
20216        .detach();
20217    }
20218
20219    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20220    /// last highlight added will be used.
20221    ///
20222    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20223    pub fn highlight_rows<T: 'static>(
20224        &mut self,
20225        range: Range<Anchor>,
20226        color: Hsla,
20227        options: RowHighlightOptions,
20228        cx: &mut Context<Self>,
20229    ) {
20230        let snapshot = self.buffer().read(cx).snapshot(cx);
20231        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20232        let ix = row_highlights.binary_search_by(|highlight| {
20233            Ordering::Equal
20234                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20235                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20236        });
20237
20238        if let Err(mut ix) = ix {
20239            let index = post_inc(&mut self.highlight_order);
20240
20241            // If this range intersects with the preceding highlight, then merge it with
20242            // the preceding highlight. Otherwise insert a new highlight.
20243            let mut merged = false;
20244            if ix > 0 {
20245                let prev_highlight = &mut row_highlights[ix - 1];
20246                if prev_highlight
20247                    .range
20248                    .end
20249                    .cmp(&range.start, &snapshot)
20250                    .is_ge()
20251                {
20252                    ix -= 1;
20253                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20254                        prev_highlight.range.end = range.end;
20255                    }
20256                    merged = true;
20257                    prev_highlight.index = index;
20258                    prev_highlight.color = color;
20259                    prev_highlight.options = options;
20260                }
20261            }
20262
20263            if !merged {
20264                row_highlights.insert(
20265                    ix,
20266                    RowHighlight {
20267                        range,
20268                        index,
20269                        color,
20270                        options,
20271                        type_id: TypeId::of::<T>(),
20272                    },
20273                );
20274            }
20275
20276            // If any of the following highlights intersect with this one, merge them.
20277            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20278                let highlight = &row_highlights[ix];
20279                if next_highlight
20280                    .range
20281                    .start
20282                    .cmp(&highlight.range.end, &snapshot)
20283                    .is_le()
20284                {
20285                    if next_highlight
20286                        .range
20287                        .end
20288                        .cmp(&highlight.range.end, &snapshot)
20289                        .is_gt()
20290                    {
20291                        row_highlights[ix].range.end = next_highlight.range.end;
20292                    }
20293                    row_highlights.remove(ix + 1);
20294                } else {
20295                    break;
20296                }
20297            }
20298        }
20299    }
20300
20301    /// Remove any highlighted row ranges of the given type that intersect the
20302    /// given ranges.
20303    pub fn remove_highlighted_rows<T: 'static>(
20304        &mut self,
20305        ranges_to_remove: Vec<Range<Anchor>>,
20306        cx: &mut Context<Self>,
20307    ) {
20308        let snapshot = self.buffer().read(cx).snapshot(cx);
20309        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20310        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20311        row_highlights.retain(|highlight| {
20312            while let Some(range_to_remove) = ranges_to_remove.peek() {
20313                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20314                    Ordering::Less | Ordering::Equal => {
20315                        ranges_to_remove.next();
20316                    }
20317                    Ordering::Greater => {
20318                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20319                            Ordering::Less | Ordering::Equal => {
20320                                return false;
20321                            }
20322                            Ordering::Greater => break,
20323                        }
20324                    }
20325                }
20326            }
20327
20328            true
20329        })
20330    }
20331
20332    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20333    pub fn clear_row_highlights<T: 'static>(&mut self) {
20334        self.highlighted_rows.remove(&TypeId::of::<T>());
20335    }
20336
20337    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20338    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20339        self.highlighted_rows
20340            .get(&TypeId::of::<T>())
20341            .map_or(&[] as &[_], |vec| vec.as_slice())
20342            .iter()
20343            .map(|highlight| (highlight.range.clone(), highlight.color))
20344    }
20345
20346    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20347    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20348    /// Allows to ignore certain kinds of highlights.
20349    pub fn highlighted_display_rows(
20350        &self,
20351        window: &mut Window,
20352        cx: &mut App,
20353    ) -> BTreeMap<DisplayRow, LineHighlight> {
20354        let snapshot = self.snapshot(window, cx);
20355        let mut used_highlight_orders = HashMap::default();
20356        self.highlighted_rows
20357            .iter()
20358            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20359            .fold(
20360                BTreeMap::<DisplayRow, LineHighlight>::new(),
20361                |mut unique_rows, highlight| {
20362                    let start = highlight.range.start.to_display_point(&snapshot);
20363                    let end = highlight.range.end.to_display_point(&snapshot);
20364                    let start_row = start.row().0;
20365                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20366                        && end.column() == 0
20367                    {
20368                        end.row().0.saturating_sub(1)
20369                    } else {
20370                        end.row().0
20371                    };
20372                    for row in start_row..=end_row {
20373                        let used_index =
20374                            used_highlight_orders.entry(row).or_insert(highlight.index);
20375                        if highlight.index >= *used_index {
20376                            *used_index = highlight.index;
20377                            unique_rows.insert(
20378                                DisplayRow(row),
20379                                LineHighlight {
20380                                    include_gutter: highlight.options.include_gutter,
20381                                    border: None,
20382                                    background: highlight.color.into(),
20383                                    type_id: Some(highlight.type_id),
20384                                },
20385                            );
20386                        }
20387                    }
20388                    unique_rows
20389                },
20390            )
20391    }
20392
20393    pub fn highlighted_display_row_for_autoscroll(
20394        &self,
20395        snapshot: &DisplaySnapshot,
20396    ) -> Option<DisplayRow> {
20397        self.highlighted_rows
20398            .values()
20399            .flat_map(|highlighted_rows| highlighted_rows.iter())
20400            .filter_map(|highlight| {
20401                if highlight.options.autoscroll {
20402                    Some(highlight.range.start.to_display_point(snapshot).row())
20403                } else {
20404                    None
20405                }
20406            })
20407            .min()
20408    }
20409
20410    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20411        self.highlight_background::<SearchWithinRange>(
20412            ranges,
20413            |colors| colors.colors().editor_document_highlight_read_background,
20414            cx,
20415        )
20416    }
20417
20418    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20419        self.breadcrumb_header = Some(new_header);
20420    }
20421
20422    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20423        self.clear_background_highlights::<SearchWithinRange>(cx);
20424    }
20425
20426    pub fn highlight_background<T: 'static>(
20427        &mut self,
20428        ranges: &[Range<Anchor>],
20429        color_fetcher: fn(&Theme) -> Hsla,
20430        cx: &mut Context<Self>,
20431    ) {
20432        self.background_highlights.insert(
20433            HighlightKey::Type(TypeId::of::<T>()),
20434            (color_fetcher, Arc::from(ranges)),
20435        );
20436        self.scrollbar_marker_state.dirty = true;
20437        cx.notify();
20438    }
20439
20440    pub fn highlight_background_key<T: 'static>(
20441        &mut self,
20442        key: usize,
20443        ranges: &[Range<Anchor>],
20444        color_fetcher: fn(&Theme) -> Hsla,
20445        cx: &mut Context<Self>,
20446    ) {
20447        self.background_highlights.insert(
20448            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20449            (color_fetcher, Arc::from(ranges)),
20450        );
20451        self.scrollbar_marker_state.dirty = true;
20452        cx.notify();
20453    }
20454
20455    pub fn clear_background_highlights<T: 'static>(
20456        &mut self,
20457        cx: &mut Context<Self>,
20458    ) -> Option<BackgroundHighlight> {
20459        let text_highlights = self
20460            .background_highlights
20461            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20462        if !text_highlights.1.is_empty() {
20463            self.scrollbar_marker_state.dirty = true;
20464            cx.notify();
20465        }
20466        Some(text_highlights)
20467    }
20468
20469    pub fn highlight_gutter<T: 'static>(
20470        &mut self,
20471        ranges: impl Into<Vec<Range<Anchor>>>,
20472        color_fetcher: fn(&App) -> Hsla,
20473        cx: &mut Context<Self>,
20474    ) {
20475        self.gutter_highlights
20476            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20477        cx.notify();
20478    }
20479
20480    pub fn clear_gutter_highlights<T: 'static>(
20481        &mut self,
20482        cx: &mut Context<Self>,
20483    ) -> Option<GutterHighlight> {
20484        cx.notify();
20485        self.gutter_highlights.remove(&TypeId::of::<T>())
20486    }
20487
20488    pub fn insert_gutter_highlight<T: 'static>(
20489        &mut self,
20490        range: Range<Anchor>,
20491        color_fetcher: fn(&App) -> Hsla,
20492        cx: &mut Context<Self>,
20493    ) {
20494        let snapshot = self.buffer().read(cx).snapshot(cx);
20495        let mut highlights = self
20496            .gutter_highlights
20497            .remove(&TypeId::of::<T>())
20498            .map(|(_, highlights)| highlights)
20499            .unwrap_or_default();
20500        let ix = highlights.binary_search_by(|highlight| {
20501            Ordering::Equal
20502                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20503                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20504        });
20505        if let Err(ix) = ix {
20506            highlights.insert(ix, range);
20507        }
20508        self.gutter_highlights
20509            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20510    }
20511
20512    pub fn remove_gutter_highlights<T: 'static>(
20513        &mut self,
20514        ranges_to_remove: Vec<Range<Anchor>>,
20515        cx: &mut Context<Self>,
20516    ) {
20517        let snapshot = self.buffer().read(cx).snapshot(cx);
20518        let Some((color_fetcher, mut gutter_highlights)) =
20519            self.gutter_highlights.remove(&TypeId::of::<T>())
20520        else {
20521            return;
20522        };
20523        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20524        gutter_highlights.retain(|highlight| {
20525            while let Some(range_to_remove) = ranges_to_remove.peek() {
20526                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20527                    Ordering::Less | Ordering::Equal => {
20528                        ranges_to_remove.next();
20529                    }
20530                    Ordering::Greater => {
20531                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20532                            Ordering::Less | Ordering::Equal => {
20533                                return false;
20534                            }
20535                            Ordering::Greater => break,
20536                        }
20537                    }
20538                }
20539            }
20540
20541            true
20542        });
20543        self.gutter_highlights
20544            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20545    }
20546
20547    #[cfg(feature = "test-support")]
20548    pub fn all_text_highlights(
20549        &self,
20550        window: &mut Window,
20551        cx: &mut Context<Self>,
20552    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20553        let snapshot = self.snapshot(window, cx);
20554        self.display_map.update(cx, |display_map, _| {
20555            display_map
20556                .all_text_highlights()
20557                .map(|highlight| {
20558                    let (style, ranges) = highlight.as_ref();
20559                    (
20560                        *style,
20561                        ranges
20562                            .iter()
20563                            .map(|range| range.clone().to_display_points(&snapshot))
20564                            .collect(),
20565                    )
20566                })
20567                .collect()
20568        })
20569    }
20570
20571    #[cfg(feature = "test-support")]
20572    pub fn all_text_background_highlights(
20573        &self,
20574        window: &mut Window,
20575        cx: &mut Context<Self>,
20576    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20577        let snapshot = self.snapshot(window, cx);
20578        let buffer = &snapshot.buffer_snapshot();
20579        let start = buffer.anchor_before(0);
20580        let end = buffer.anchor_after(buffer.len());
20581        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20582    }
20583
20584    #[cfg(any(test, feature = "test-support"))]
20585    pub fn sorted_background_highlights_in_range(
20586        &self,
20587        search_range: Range<Anchor>,
20588        display_snapshot: &DisplaySnapshot,
20589        theme: &Theme,
20590    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20591        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20592        res.sort_by(|a, b| {
20593            a.0.start
20594                .cmp(&b.0.start)
20595                .then_with(|| a.0.end.cmp(&b.0.end))
20596                .then_with(|| a.1.cmp(&b.1))
20597        });
20598        res
20599    }
20600
20601    #[cfg(feature = "test-support")]
20602    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20603        let snapshot = self.buffer().read(cx).snapshot(cx);
20604
20605        let highlights = self
20606            .background_highlights
20607            .get(&HighlightKey::Type(TypeId::of::<
20608                items::BufferSearchHighlights,
20609            >()));
20610
20611        if let Some((_color, ranges)) = highlights {
20612            ranges
20613                .iter()
20614                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20615                .collect_vec()
20616        } else {
20617            vec![]
20618        }
20619    }
20620
20621    fn document_highlights_for_position<'a>(
20622        &'a self,
20623        position: Anchor,
20624        buffer: &'a MultiBufferSnapshot,
20625    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20626        let read_highlights = self
20627            .background_highlights
20628            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20629            .map(|h| &h.1);
20630        let write_highlights = self
20631            .background_highlights
20632            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20633            .map(|h| &h.1);
20634        let left_position = position.bias_left(buffer);
20635        let right_position = position.bias_right(buffer);
20636        read_highlights
20637            .into_iter()
20638            .chain(write_highlights)
20639            .flat_map(move |ranges| {
20640                let start_ix = match ranges.binary_search_by(|probe| {
20641                    let cmp = probe.end.cmp(&left_position, buffer);
20642                    if cmp.is_ge() {
20643                        Ordering::Greater
20644                    } else {
20645                        Ordering::Less
20646                    }
20647                }) {
20648                    Ok(i) | Err(i) => i,
20649                };
20650
20651                ranges[start_ix..]
20652                    .iter()
20653                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20654            })
20655    }
20656
20657    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20658        self.background_highlights
20659            .get(&HighlightKey::Type(TypeId::of::<T>()))
20660            .is_some_and(|(_, highlights)| !highlights.is_empty())
20661    }
20662
20663    /// Returns all background highlights for a given range.
20664    ///
20665    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20666    pub fn background_highlights_in_range(
20667        &self,
20668        search_range: Range<Anchor>,
20669        display_snapshot: &DisplaySnapshot,
20670        theme: &Theme,
20671    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20672        let mut results = Vec::new();
20673        for (color_fetcher, ranges) in self.background_highlights.values() {
20674            let color = color_fetcher(theme);
20675            let start_ix = match ranges.binary_search_by(|probe| {
20676                let cmp = probe
20677                    .end
20678                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20679                if cmp.is_gt() {
20680                    Ordering::Greater
20681                } else {
20682                    Ordering::Less
20683                }
20684            }) {
20685                Ok(i) | Err(i) => i,
20686            };
20687            for range in &ranges[start_ix..] {
20688                if range
20689                    .start
20690                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20691                    .is_ge()
20692                {
20693                    break;
20694                }
20695
20696                let start = range.start.to_display_point(display_snapshot);
20697                let end = range.end.to_display_point(display_snapshot);
20698                results.push((start..end, color))
20699            }
20700        }
20701        results
20702    }
20703
20704    pub fn gutter_highlights_in_range(
20705        &self,
20706        search_range: Range<Anchor>,
20707        display_snapshot: &DisplaySnapshot,
20708        cx: &App,
20709    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20710        let mut results = Vec::new();
20711        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20712            let color = color_fetcher(cx);
20713            let start_ix = match ranges.binary_search_by(|probe| {
20714                let cmp = probe
20715                    .end
20716                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20717                if cmp.is_gt() {
20718                    Ordering::Greater
20719                } else {
20720                    Ordering::Less
20721                }
20722            }) {
20723                Ok(i) | Err(i) => i,
20724            };
20725            for range in &ranges[start_ix..] {
20726                if range
20727                    .start
20728                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20729                    .is_ge()
20730                {
20731                    break;
20732                }
20733
20734                let start = range.start.to_display_point(display_snapshot);
20735                let end = range.end.to_display_point(display_snapshot);
20736                results.push((start..end, color))
20737            }
20738        }
20739        results
20740    }
20741
20742    /// Get the text ranges corresponding to the redaction query
20743    pub fn redacted_ranges(
20744        &self,
20745        search_range: Range<Anchor>,
20746        display_snapshot: &DisplaySnapshot,
20747        cx: &App,
20748    ) -> Vec<Range<DisplayPoint>> {
20749        display_snapshot
20750            .buffer_snapshot()
20751            .redacted_ranges(search_range, |file| {
20752                if let Some(file) = file {
20753                    file.is_private()
20754                        && EditorSettings::get(
20755                            Some(SettingsLocation {
20756                                worktree_id: file.worktree_id(cx),
20757                                path: file.path().as_ref(),
20758                            }),
20759                            cx,
20760                        )
20761                        .redact_private_values
20762                } else {
20763                    false
20764                }
20765            })
20766            .map(|range| {
20767                range.start.to_display_point(display_snapshot)
20768                    ..range.end.to_display_point(display_snapshot)
20769            })
20770            .collect()
20771    }
20772
20773    pub fn highlight_text_key<T: 'static>(
20774        &mut self,
20775        key: usize,
20776        ranges: Vec<Range<Anchor>>,
20777        style: HighlightStyle,
20778        cx: &mut Context<Self>,
20779    ) {
20780        self.display_map.update(cx, |map, _| {
20781            map.highlight_text(
20782                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20783                ranges,
20784                style,
20785            );
20786        });
20787        cx.notify();
20788    }
20789
20790    pub fn highlight_text<T: 'static>(
20791        &mut self,
20792        ranges: Vec<Range<Anchor>>,
20793        style: HighlightStyle,
20794        cx: &mut Context<Self>,
20795    ) {
20796        self.display_map.update(cx, |map, _| {
20797            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20798        });
20799        cx.notify();
20800    }
20801
20802    pub fn text_highlights<'a, T: 'static>(
20803        &'a self,
20804        cx: &'a App,
20805    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20806        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20807    }
20808
20809    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20810        let cleared = self
20811            .display_map
20812            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20813        if cleared {
20814            cx.notify();
20815        }
20816    }
20817
20818    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20819        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20820            && self.focus_handle.is_focused(window)
20821    }
20822
20823    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20824        self.show_cursor_when_unfocused = is_enabled;
20825        cx.notify();
20826    }
20827
20828    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20829        cx.notify();
20830    }
20831
20832    fn on_debug_session_event(
20833        &mut self,
20834        _session: Entity<Session>,
20835        event: &SessionEvent,
20836        cx: &mut Context<Self>,
20837    ) {
20838        if let SessionEvent::InvalidateInlineValue = event {
20839            self.refresh_inline_values(cx);
20840        }
20841    }
20842
20843    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20844        let Some(project) = self.project.clone() else {
20845            return;
20846        };
20847
20848        if !self.inline_value_cache.enabled {
20849            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20850            self.splice_inlays(&inlays, Vec::new(), cx);
20851            return;
20852        }
20853
20854        let current_execution_position = self
20855            .highlighted_rows
20856            .get(&TypeId::of::<ActiveDebugLine>())
20857            .and_then(|lines| lines.last().map(|line| line.range.end));
20858
20859        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20860            let inline_values = editor
20861                .update(cx, |editor, cx| {
20862                    let Some(current_execution_position) = current_execution_position else {
20863                        return Some(Task::ready(Ok(Vec::new())));
20864                    };
20865
20866                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20867                        let snapshot = buffer.snapshot(cx);
20868
20869                        let excerpt = snapshot.excerpt_containing(
20870                            current_execution_position..current_execution_position,
20871                        )?;
20872
20873                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20874                    })?;
20875
20876                    let range =
20877                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20878
20879                    project.inline_values(buffer, range, cx)
20880                })
20881                .ok()
20882                .flatten()?
20883                .await
20884                .context("refreshing debugger inlays")
20885                .log_err()?;
20886
20887            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20888
20889            for (buffer_id, inline_value) in inline_values
20890                .into_iter()
20891                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20892            {
20893                buffer_inline_values
20894                    .entry(buffer_id)
20895                    .or_default()
20896                    .push(inline_value);
20897            }
20898
20899            editor
20900                .update(cx, |editor, cx| {
20901                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20902                    let mut new_inlays = Vec::default();
20903
20904                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20905                        let buffer_id = buffer_snapshot.remote_id();
20906                        buffer_inline_values
20907                            .get(&buffer_id)
20908                            .into_iter()
20909                            .flatten()
20910                            .for_each(|hint| {
20911                                let inlay = Inlay::debugger(
20912                                    post_inc(&mut editor.next_inlay_id),
20913                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20914                                    hint.text(),
20915                                );
20916                                if !inlay.text().chars().contains(&'\n') {
20917                                    new_inlays.push(inlay);
20918                                }
20919                            });
20920                    }
20921
20922                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20923                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20924
20925                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20926                })
20927                .ok()?;
20928            Some(())
20929        });
20930    }
20931
20932    fn on_buffer_event(
20933        &mut self,
20934        multibuffer: &Entity<MultiBuffer>,
20935        event: &multi_buffer::Event,
20936        window: &mut Window,
20937        cx: &mut Context<Self>,
20938    ) {
20939        match event {
20940            multi_buffer::Event::Edited { edited_buffer } => {
20941                self.scrollbar_marker_state.dirty = true;
20942                self.active_indent_guides_state.dirty = true;
20943                self.refresh_active_diagnostics(cx);
20944                self.refresh_code_actions(window, cx);
20945                self.refresh_selected_text_highlights(true, window, cx);
20946                self.refresh_single_line_folds(window, cx);
20947                self.refresh_matching_bracket_highlights(window, cx);
20948                if self.has_active_edit_prediction() {
20949                    self.update_visible_edit_prediction(window, cx);
20950                }
20951
20952                if let Some(buffer) = edited_buffer {
20953                    if buffer.read(cx).file().is_none() {
20954                        cx.emit(EditorEvent::TitleChanged);
20955                    }
20956
20957                    if self.project.is_some() {
20958                        let buffer_id = buffer.read(cx).remote_id();
20959                        self.register_buffer(buffer_id, cx);
20960                        self.update_lsp_data(Some(buffer_id), window, cx);
20961                        self.refresh_inlay_hints(
20962                            InlayHintRefreshReason::BufferEdited(buffer_id),
20963                            cx,
20964                        );
20965                    }
20966                }
20967
20968                cx.emit(EditorEvent::BufferEdited);
20969                cx.emit(SearchEvent::MatchesInvalidated);
20970
20971                let Some(project) = &self.project else { return };
20972                let (telemetry, is_via_ssh) = {
20973                    let project = project.read(cx);
20974                    let telemetry = project.client().telemetry().clone();
20975                    let is_via_ssh = project.is_via_remote_server();
20976                    (telemetry, is_via_ssh)
20977                };
20978                telemetry.log_edit_event("editor", is_via_ssh);
20979            }
20980            multi_buffer::Event::ExcerptsAdded {
20981                buffer,
20982                predecessor,
20983                excerpts,
20984            } => {
20985                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20986                let buffer_id = buffer.read(cx).remote_id();
20987                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20988                    && let Some(project) = &self.project
20989                {
20990                    update_uncommitted_diff_for_buffer(
20991                        cx.entity(),
20992                        project,
20993                        [buffer.clone()],
20994                        self.buffer.clone(),
20995                        cx,
20996                    )
20997                    .detach();
20998                }
20999                self.update_lsp_data(Some(buffer_id), window, cx);
21000                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21001                cx.emit(EditorEvent::ExcerptsAdded {
21002                    buffer: buffer.clone(),
21003                    predecessor: *predecessor,
21004                    excerpts: excerpts.clone(),
21005                });
21006            }
21007            multi_buffer::Event::ExcerptsRemoved {
21008                ids,
21009                removed_buffer_ids,
21010            } => {
21011                if let Some(inlay_hints) = &mut self.inlay_hints {
21012                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21013                }
21014                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21015                for buffer_id in removed_buffer_ids {
21016                    self.registered_buffers.remove(buffer_id);
21017                }
21018                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21019                cx.emit(EditorEvent::ExcerptsRemoved {
21020                    ids: ids.clone(),
21021                    removed_buffer_ids: removed_buffer_ids.clone(),
21022                });
21023            }
21024            multi_buffer::Event::ExcerptsEdited {
21025                excerpt_ids,
21026                buffer_ids,
21027            } => {
21028                self.display_map.update(cx, |map, cx| {
21029                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21030                });
21031                cx.emit(EditorEvent::ExcerptsEdited {
21032                    ids: excerpt_ids.clone(),
21033                });
21034            }
21035            multi_buffer::Event::ExcerptsExpanded { ids } => {
21036                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21037                self.refresh_document_highlights(cx);
21038                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21039            }
21040            multi_buffer::Event::Reparsed(buffer_id) => {
21041                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21042                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21043
21044                cx.emit(EditorEvent::Reparsed(*buffer_id));
21045            }
21046            multi_buffer::Event::DiffHunksToggled => {
21047                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21048            }
21049            multi_buffer::Event::LanguageChanged(buffer_id) => {
21050                self.registered_buffers.remove(&buffer_id);
21051                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21052                cx.emit(EditorEvent::Reparsed(*buffer_id));
21053                cx.notify();
21054            }
21055            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21056            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21057            multi_buffer::Event::FileHandleChanged
21058            | multi_buffer::Event::Reloaded
21059            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21060            multi_buffer::Event::DiagnosticsUpdated => {
21061                self.update_diagnostics_state(window, cx);
21062            }
21063            _ => {}
21064        };
21065    }
21066
21067    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21068        if !self.diagnostics_enabled() {
21069            return;
21070        }
21071        self.refresh_active_diagnostics(cx);
21072        self.refresh_inline_diagnostics(true, window, cx);
21073        self.scrollbar_marker_state.dirty = true;
21074        cx.notify();
21075    }
21076
21077    pub fn start_temporary_diff_override(&mut self) {
21078        self.load_diff_task.take();
21079        self.temporary_diff_override = true;
21080    }
21081
21082    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21083        self.temporary_diff_override = false;
21084        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21085        self.buffer.update(cx, |buffer, cx| {
21086            buffer.set_all_diff_hunks_collapsed(cx);
21087        });
21088
21089        if let Some(project) = self.project.clone() {
21090            self.load_diff_task = Some(
21091                update_uncommitted_diff_for_buffer(
21092                    cx.entity(),
21093                    &project,
21094                    self.buffer.read(cx).all_buffers(),
21095                    self.buffer.clone(),
21096                    cx,
21097                )
21098                .shared(),
21099            );
21100        }
21101    }
21102
21103    fn on_display_map_changed(
21104        &mut self,
21105        _: Entity<DisplayMap>,
21106        _: &mut Window,
21107        cx: &mut Context<Self>,
21108    ) {
21109        cx.notify();
21110    }
21111
21112    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21113        if self.diagnostics_enabled() {
21114            let new_severity = EditorSettings::get_global(cx)
21115                .diagnostics_max_severity
21116                .unwrap_or(DiagnosticSeverity::Hint);
21117            self.set_max_diagnostics_severity(new_severity, cx);
21118        }
21119        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21120        self.update_edit_prediction_settings(cx);
21121        self.refresh_edit_prediction(true, false, window, cx);
21122        self.refresh_inline_values(cx);
21123        self.refresh_inlay_hints(
21124            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21125                self.selections.newest_anchor().head(),
21126                &self.buffer.read(cx).snapshot(cx),
21127                cx,
21128            )),
21129            cx,
21130        );
21131
21132        let old_cursor_shape = self.cursor_shape;
21133        let old_show_breadcrumbs = self.show_breadcrumbs;
21134
21135        {
21136            let editor_settings = EditorSettings::get_global(cx);
21137            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21138            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21139            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21140            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21141        }
21142
21143        if old_cursor_shape != self.cursor_shape {
21144            cx.emit(EditorEvent::CursorShapeChanged);
21145        }
21146
21147        if old_show_breadcrumbs != self.show_breadcrumbs {
21148            cx.emit(EditorEvent::BreadcrumbsChanged);
21149        }
21150
21151        let project_settings = ProjectSettings::get_global(cx);
21152        self.serialize_dirty_buffers =
21153            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21154
21155        if self.mode.is_full() {
21156            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21157            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21158            if self.show_inline_diagnostics != show_inline_diagnostics {
21159                self.show_inline_diagnostics = show_inline_diagnostics;
21160                self.refresh_inline_diagnostics(false, window, cx);
21161            }
21162
21163            if self.git_blame_inline_enabled != inline_blame_enabled {
21164                self.toggle_git_blame_inline_internal(false, window, cx);
21165            }
21166
21167            let minimap_settings = EditorSettings::get_global(cx).minimap;
21168            if self.minimap_visibility != MinimapVisibility::Disabled {
21169                if self.minimap_visibility.settings_visibility()
21170                    != minimap_settings.minimap_enabled()
21171                {
21172                    self.set_minimap_visibility(
21173                        MinimapVisibility::for_mode(self.mode(), cx),
21174                        window,
21175                        cx,
21176                    );
21177                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21178                    minimap_entity.update(cx, |minimap_editor, cx| {
21179                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21180                    })
21181                }
21182            }
21183        }
21184
21185        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21186            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21187        }) {
21188            if !inlay_splice.is_empty() {
21189                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21190            }
21191            self.refresh_colors_for_visible_range(None, window, cx);
21192        }
21193
21194        cx.notify();
21195    }
21196
21197    pub fn set_searchable(&mut self, searchable: bool) {
21198        self.searchable = searchable;
21199    }
21200
21201    pub fn searchable(&self) -> bool {
21202        self.searchable
21203    }
21204
21205    pub fn open_excerpts_in_split(
21206        &mut self,
21207        _: &OpenExcerptsSplit,
21208        window: &mut Window,
21209        cx: &mut Context<Self>,
21210    ) {
21211        self.open_excerpts_common(None, true, window, cx)
21212    }
21213
21214    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21215        self.open_excerpts_common(None, false, window, cx)
21216    }
21217
21218    fn open_excerpts_common(
21219        &mut self,
21220        jump_data: Option<JumpData>,
21221        split: bool,
21222        window: &mut Window,
21223        cx: &mut Context<Self>,
21224    ) {
21225        let Some(workspace) = self.workspace() else {
21226            cx.propagate();
21227            return;
21228        };
21229
21230        if self.buffer.read(cx).is_singleton() {
21231            cx.propagate();
21232            return;
21233        }
21234
21235        let mut new_selections_by_buffer = HashMap::default();
21236        match &jump_data {
21237            Some(JumpData::MultiBufferPoint {
21238                excerpt_id,
21239                position,
21240                anchor,
21241                line_offset_from_top,
21242            }) => {
21243                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21244                if let Some(buffer) = multi_buffer_snapshot
21245                    .buffer_id_for_excerpt(*excerpt_id)
21246                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21247                {
21248                    let buffer_snapshot = buffer.read(cx).snapshot();
21249                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21250                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21251                    } else {
21252                        buffer_snapshot.clip_point(*position, Bias::Left)
21253                    };
21254                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21255                    new_selections_by_buffer.insert(
21256                        buffer,
21257                        (
21258                            vec![jump_to_offset..jump_to_offset],
21259                            Some(*line_offset_from_top),
21260                        ),
21261                    );
21262                }
21263            }
21264            Some(JumpData::MultiBufferRow {
21265                row,
21266                line_offset_from_top,
21267            }) => {
21268                let point = MultiBufferPoint::new(row.0, 0);
21269                if let Some((buffer, buffer_point, _)) =
21270                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21271                {
21272                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21273                    new_selections_by_buffer
21274                        .entry(buffer)
21275                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21276                        .0
21277                        .push(buffer_offset..buffer_offset)
21278                }
21279            }
21280            None => {
21281                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21282                let multi_buffer = self.buffer.read(cx);
21283                for selection in selections {
21284                    for (snapshot, range, _, anchor) in multi_buffer
21285                        .snapshot(cx)
21286                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21287                    {
21288                        if let Some(anchor) = anchor {
21289                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21290                            else {
21291                                continue;
21292                            };
21293                            let offset = text::ToOffset::to_offset(
21294                                &anchor.text_anchor,
21295                                &buffer_handle.read(cx).snapshot(),
21296                            );
21297                            let range = offset..offset;
21298                            new_selections_by_buffer
21299                                .entry(buffer_handle)
21300                                .or_insert((Vec::new(), None))
21301                                .0
21302                                .push(range)
21303                        } else {
21304                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21305                            else {
21306                                continue;
21307                            };
21308                            new_selections_by_buffer
21309                                .entry(buffer_handle)
21310                                .or_insert((Vec::new(), None))
21311                                .0
21312                                .push(range)
21313                        }
21314                    }
21315                }
21316            }
21317        }
21318
21319        new_selections_by_buffer
21320            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21321
21322        if new_selections_by_buffer.is_empty() {
21323            return;
21324        }
21325
21326        // We defer the pane interaction because we ourselves are a workspace item
21327        // and activating a new item causes the pane to call a method on us reentrantly,
21328        // which panics if we're on the stack.
21329        window.defer(cx, move |window, cx| {
21330            workspace.update(cx, |workspace, cx| {
21331                let pane = if split {
21332                    workspace.adjacent_pane(window, cx)
21333                } else {
21334                    workspace.active_pane().clone()
21335                };
21336
21337                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21338                    let editor = buffer
21339                        .read(cx)
21340                        .file()
21341                        .is_none()
21342                        .then(|| {
21343                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21344                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21345                            // Instead, we try to activate the existing editor in the pane first.
21346                            let (editor, pane_item_index) =
21347                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21348                                    let editor = item.downcast::<Editor>()?;
21349                                    let singleton_buffer =
21350                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21351                                    if singleton_buffer == buffer {
21352                                        Some((editor, i))
21353                                    } else {
21354                                        None
21355                                    }
21356                                })?;
21357                            pane.update(cx, |pane, cx| {
21358                                pane.activate_item(pane_item_index, true, true, window, cx)
21359                            });
21360                            Some(editor)
21361                        })
21362                        .flatten()
21363                        .unwrap_or_else(|| {
21364                            workspace.open_project_item::<Self>(
21365                                pane.clone(),
21366                                buffer,
21367                                true,
21368                                true,
21369                                window,
21370                                cx,
21371                            )
21372                        });
21373
21374                    editor.update(cx, |editor, cx| {
21375                        let autoscroll = match scroll_offset {
21376                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21377                            None => Autoscroll::newest(),
21378                        };
21379                        let nav_history = editor.nav_history.take();
21380                        editor.change_selections(
21381                            SelectionEffects::scroll(autoscroll),
21382                            window,
21383                            cx,
21384                            |s| {
21385                                s.select_ranges(ranges);
21386                            },
21387                        );
21388                        editor.nav_history = nav_history;
21389                    });
21390                }
21391            })
21392        });
21393    }
21394
21395    // For now, don't allow opening excerpts in buffers that aren't backed by
21396    // regular project files.
21397    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21398        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21399    }
21400
21401    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21402        let snapshot = self.buffer.read(cx).read(cx);
21403        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21404        Some(
21405            ranges
21406                .iter()
21407                .map(move |range| {
21408                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21409                })
21410                .collect(),
21411        )
21412    }
21413
21414    fn selection_replacement_ranges(
21415        &self,
21416        range: Range<OffsetUtf16>,
21417        cx: &mut App,
21418    ) -> Vec<Range<OffsetUtf16>> {
21419        let selections = self
21420            .selections
21421            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21422        let newest_selection = selections
21423            .iter()
21424            .max_by_key(|selection| selection.id)
21425            .unwrap();
21426        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21427        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21428        let snapshot = self.buffer.read(cx).read(cx);
21429        selections
21430            .into_iter()
21431            .map(|mut selection| {
21432                selection.start.0 =
21433                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21434                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21435                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21436                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21437            })
21438            .collect()
21439    }
21440
21441    fn report_editor_event(
21442        &self,
21443        reported_event: ReportEditorEvent,
21444        file_extension: Option<String>,
21445        cx: &App,
21446    ) {
21447        if cfg!(any(test, feature = "test-support")) {
21448            return;
21449        }
21450
21451        let Some(project) = &self.project else { return };
21452
21453        // If None, we are in a file without an extension
21454        let file = self
21455            .buffer
21456            .read(cx)
21457            .as_singleton()
21458            .and_then(|b| b.read(cx).file());
21459        let file_extension = file_extension.or(file
21460            .as_ref()
21461            .and_then(|file| Path::new(file.file_name(cx)).extension())
21462            .and_then(|e| e.to_str())
21463            .map(|a| a.to_string()));
21464
21465        let vim_mode = vim_flavor(cx).is_some();
21466
21467        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21468        let copilot_enabled = edit_predictions_provider
21469            == language::language_settings::EditPredictionProvider::Copilot;
21470        let copilot_enabled_for_language = self
21471            .buffer
21472            .read(cx)
21473            .language_settings(cx)
21474            .show_edit_predictions;
21475
21476        let project = project.read(cx);
21477        let event_type = reported_event.event_type();
21478
21479        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21480            telemetry::event!(
21481                event_type,
21482                type = if auto_saved {"autosave"} else {"manual"},
21483                file_extension,
21484                vim_mode,
21485                copilot_enabled,
21486                copilot_enabled_for_language,
21487                edit_predictions_provider,
21488                is_via_ssh = project.is_via_remote_server(),
21489            );
21490        } else {
21491            telemetry::event!(
21492                event_type,
21493                file_extension,
21494                vim_mode,
21495                copilot_enabled,
21496                copilot_enabled_for_language,
21497                edit_predictions_provider,
21498                is_via_ssh = project.is_via_remote_server(),
21499            );
21500        };
21501    }
21502
21503    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21504    /// with each line being an array of {text, highlight} objects.
21505    fn copy_highlight_json(
21506        &mut self,
21507        _: &CopyHighlightJson,
21508        window: &mut Window,
21509        cx: &mut Context<Self>,
21510    ) {
21511        #[derive(Serialize)]
21512        struct Chunk<'a> {
21513            text: String,
21514            highlight: Option<&'a str>,
21515        }
21516
21517        let snapshot = self.buffer.read(cx).snapshot(cx);
21518        let range = self
21519            .selected_text_range(false, window, cx)
21520            .and_then(|selection| {
21521                if selection.range.is_empty() {
21522                    None
21523                } else {
21524                    Some(
21525                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21526                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21527                    )
21528                }
21529            })
21530            .unwrap_or_else(|| 0..snapshot.len());
21531
21532        let chunks = snapshot.chunks(range, true);
21533        let mut lines = Vec::new();
21534        let mut line: VecDeque<Chunk> = VecDeque::new();
21535
21536        let Some(style) = self.style.as_ref() else {
21537            return;
21538        };
21539
21540        for chunk in chunks {
21541            let highlight = chunk
21542                .syntax_highlight_id
21543                .and_then(|id| id.name(&style.syntax));
21544            let mut chunk_lines = chunk.text.split('\n').peekable();
21545            while let Some(text) = chunk_lines.next() {
21546                let mut merged_with_last_token = false;
21547                if let Some(last_token) = line.back_mut()
21548                    && last_token.highlight == highlight
21549                {
21550                    last_token.text.push_str(text);
21551                    merged_with_last_token = true;
21552                }
21553
21554                if !merged_with_last_token {
21555                    line.push_back(Chunk {
21556                        text: text.into(),
21557                        highlight,
21558                    });
21559                }
21560
21561                if chunk_lines.peek().is_some() {
21562                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21563                        line.pop_front();
21564                    }
21565                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21566                        line.pop_back();
21567                    }
21568
21569                    lines.push(mem::take(&mut line));
21570                }
21571            }
21572        }
21573
21574        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21575            return;
21576        };
21577        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21578    }
21579
21580    pub fn open_context_menu(
21581        &mut self,
21582        _: &OpenContextMenu,
21583        window: &mut Window,
21584        cx: &mut Context<Self>,
21585    ) {
21586        self.request_autoscroll(Autoscroll::newest(), cx);
21587        let position = self
21588            .selections
21589            .newest_display(&self.display_snapshot(cx))
21590            .start;
21591        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21592    }
21593
21594    pub fn replay_insert_event(
21595        &mut self,
21596        text: &str,
21597        relative_utf16_range: Option<Range<isize>>,
21598        window: &mut Window,
21599        cx: &mut Context<Self>,
21600    ) {
21601        if !self.input_enabled {
21602            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21603            return;
21604        }
21605        if let Some(relative_utf16_range) = relative_utf16_range {
21606            let selections = self
21607                .selections
21608                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21609            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21610                let new_ranges = selections.into_iter().map(|range| {
21611                    let start = OffsetUtf16(
21612                        range
21613                            .head()
21614                            .0
21615                            .saturating_add_signed(relative_utf16_range.start),
21616                    );
21617                    let end = OffsetUtf16(
21618                        range
21619                            .head()
21620                            .0
21621                            .saturating_add_signed(relative_utf16_range.end),
21622                    );
21623                    start..end
21624                });
21625                s.select_ranges(new_ranges);
21626            });
21627        }
21628
21629        self.handle_input(text, window, cx);
21630    }
21631
21632    pub fn is_focused(&self, window: &Window) -> bool {
21633        self.focus_handle.is_focused(window)
21634    }
21635
21636    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21637        cx.emit(EditorEvent::Focused);
21638
21639        if let Some(descendant) = self
21640            .last_focused_descendant
21641            .take()
21642            .and_then(|descendant| descendant.upgrade())
21643        {
21644            window.focus(&descendant);
21645        } else {
21646            if let Some(blame) = self.blame.as_ref() {
21647                blame.update(cx, GitBlame::focus)
21648            }
21649
21650            self.blink_manager.update(cx, BlinkManager::enable);
21651            self.show_cursor_names(window, cx);
21652            self.buffer.update(cx, |buffer, cx| {
21653                buffer.finalize_last_transaction(cx);
21654                if self.leader_id.is_none() {
21655                    buffer.set_active_selections(
21656                        &self.selections.disjoint_anchors_arc(),
21657                        self.selections.line_mode(),
21658                        self.cursor_shape,
21659                        cx,
21660                    );
21661                }
21662            });
21663        }
21664    }
21665
21666    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21667        cx.emit(EditorEvent::FocusedIn)
21668    }
21669
21670    fn handle_focus_out(
21671        &mut self,
21672        event: FocusOutEvent,
21673        _window: &mut Window,
21674        cx: &mut Context<Self>,
21675    ) {
21676        if event.blurred != self.focus_handle {
21677            self.last_focused_descendant = Some(event.blurred);
21678        }
21679        self.selection_drag_state = SelectionDragState::None;
21680        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21681    }
21682
21683    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21684        self.blink_manager.update(cx, BlinkManager::disable);
21685        self.buffer
21686            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21687
21688        if let Some(blame) = self.blame.as_ref() {
21689            blame.update(cx, GitBlame::blur)
21690        }
21691        if !self.hover_state.focused(window, cx) {
21692            hide_hover(self, cx);
21693        }
21694        if !self
21695            .context_menu
21696            .borrow()
21697            .as_ref()
21698            .is_some_and(|context_menu| context_menu.focused(window, cx))
21699        {
21700            self.hide_context_menu(window, cx);
21701        }
21702        self.take_active_edit_prediction(cx);
21703        cx.emit(EditorEvent::Blurred);
21704        cx.notify();
21705    }
21706
21707    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21708        let mut pending: String = window
21709            .pending_input_keystrokes()
21710            .into_iter()
21711            .flatten()
21712            .filter_map(|keystroke| {
21713                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21714                    keystroke.key_char.clone()
21715                } else {
21716                    None
21717                }
21718            })
21719            .collect();
21720
21721        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21722            pending = "".to_string();
21723        }
21724
21725        let existing_pending = self
21726            .text_highlights::<PendingInput>(cx)
21727            .map(|(_, ranges)| ranges.to_vec());
21728        if existing_pending.is_none() && pending.is_empty() {
21729            return;
21730        }
21731        let transaction =
21732            self.transact(window, cx, |this, window, cx| {
21733                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21734                let edits = selections
21735                    .iter()
21736                    .map(|selection| (selection.end..selection.end, pending.clone()));
21737                this.edit(edits, cx);
21738                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21739                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21740                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21741                    }));
21742                });
21743                if let Some(existing_ranges) = existing_pending {
21744                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21745                    this.edit(edits, cx);
21746                }
21747            });
21748
21749        let snapshot = self.snapshot(window, cx);
21750        let ranges = self
21751            .selections
21752            .all::<usize>(&snapshot.display_snapshot)
21753            .into_iter()
21754            .map(|selection| {
21755                snapshot.buffer_snapshot().anchor_after(selection.end)
21756                    ..snapshot
21757                        .buffer_snapshot()
21758                        .anchor_before(selection.end + pending.len())
21759            })
21760            .collect();
21761
21762        if pending.is_empty() {
21763            self.clear_highlights::<PendingInput>(cx);
21764        } else {
21765            self.highlight_text::<PendingInput>(
21766                ranges,
21767                HighlightStyle {
21768                    underline: Some(UnderlineStyle {
21769                        thickness: px(1.),
21770                        color: None,
21771                        wavy: false,
21772                    }),
21773                    ..Default::default()
21774                },
21775                cx,
21776            );
21777        }
21778
21779        self.ime_transaction = self.ime_transaction.or(transaction);
21780        if let Some(transaction) = self.ime_transaction {
21781            self.buffer.update(cx, |buffer, cx| {
21782                buffer.group_until_transaction(transaction, cx);
21783            });
21784        }
21785
21786        if self.text_highlights::<PendingInput>(cx).is_none() {
21787            self.ime_transaction.take();
21788        }
21789    }
21790
21791    pub fn register_action_renderer(
21792        &mut self,
21793        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21794    ) -> Subscription {
21795        let id = self.next_editor_action_id.post_inc();
21796        self.editor_actions
21797            .borrow_mut()
21798            .insert(id, Box::new(listener));
21799
21800        let editor_actions = self.editor_actions.clone();
21801        Subscription::new(move || {
21802            editor_actions.borrow_mut().remove(&id);
21803        })
21804    }
21805
21806    pub fn register_action<A: Action>(
21807        &mut self,
21808        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21809    ) -> Subscription {
21810        let id = self.next_editor_action_id.post_inc();
21811        let listener = Arc::new(listener);
21812        self.editor_actions.borrow_mut().insert(
21813            id,
21814            Box::new(move |_, window, _| {
21815                let listener = listener.clone();
21816                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21817                    let action = action.downcast_ref().unwrap();
21818                    if phase == DispatchPhase::Bubble {
21819                        listener(action, window, cx)
21820                    }
21821                })
21822            }),
21823        );
21824
21825        let editor_actions = self.editor_actions.clone();
21826        Subscription::new(move || {
21827            editor_actions.borrow_mut().remove(&id);
21828        })
21829    }
21830
21831    pub fn file_header_size(&self) -> u32 {
21832        FILE_HEADER_HEIGHT
21833    }
21834
21835    pub fn restore(
21836        &mut self,
21837        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21838        window: &mut Window,
21839        cx: &mut Context<Self>,
21840    ) {
21841        let workspace = self.workspace();
21842        let project = self.project();
21843        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21844            let mut tasks = Vec::new();
21845            for (buffer_id, changes) in revert_changes {
21846                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21847                    buffer.update(cx, |buffer, cx| {
21848                        buffer.edit(
21849                            changes
21850                                .into_iter()
21851                                .map(|(range, text)| (range, text.to_string())),
21852                            None,
21853                            cx,
21854                        );
21855                    });
21856
21857                    if let Some(project) =
21858                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21859                    {
21860                        project.update(cx, |project, cx| {
21861                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21862                        })
21863                    }
21864                }
21865            }
21866            tasks
21867        });
21868        cx.spawn_in(window, async move |_, cx| {
21869            for (buffer, task) in save_tasks {
21870                let result = task.await;
21871                if result.is_err() {
21872                    let Some(path) = buffer
21873                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21874                        .ok()
21875                    else {
21876                        continue;
21877                    };
21878                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21879                        let Some(task) = cx
21880                            .update_window_entity(workspace, |workspace, window, cx| {
21881                                workspace
21882                                    .open_path_preview(path, None, false, false, false, window, cx)
21883                            })
21884                            .ok()
21885                        else {
21886                            continue;
21887                        };
21888                        task.await.log_err();
21889                    }
21890                }
21891            }
21892        })
21893        .detach();
21894        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21895            selections.refresh()
21896        });
21897    }
21898
21899    pub fn to_pixel_point(
21900        &self,
21901        source: multi_buffer::Anchor,
21902        editor_snapshot: &EditorSnapshot,
21903        window: &mut Window,
21904    ) -> Option<gpui::Point<Pixels>> {
21905        let source_point = source.to_display_point(editor_snapshot);
21906        self.display_to_pixel_point(source_point, editor_snapshot, window)
21907    }
21908
21909    pub fn display_to_pixel_point(
21910        &self,
21911        source: DisplayPoint,
21912        editor_snapshot: &EditorSnapshot,
21913        window: &mut Window,
21914    ) -> Option<gpui::Point<Pixels>> {
21915        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21916        let text_layout_details = self.text_layout_details(window);
21917        let scroll_top = text_layout_details
21918            .scroll_anchor
21919            .scroll_position(editor_snapshot)
21920            .y;
21921
21922        if source.row().as_f64() < scroll_top.floor() {
21923            return None;
21924        }
21925        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21926        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21927        Some(gpui::Point::new(source_x, source_y))
21928    }
21929
21930    pub fn has_visible_completions_menu(&self) -> bool {
21931        !self.edit_prediction_preview_is_active()
21932            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21933                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21934            })
21935    }
21936
21937    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21938        if self.mode.is_minimap() {
21939            return;
21940        }
21941        self.addons
21942            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21943    }
21944
21945    pub fn unregister_addon<T: Addon>(&mut self) {
21946        self.addons.remove(&std::any::TypeId::of::<T>());
21947    }
21948
21949    pub fn addon<T: Addon>(&self) -> Option<&T> {
21950        let type_id = std::any::TypeId::of::<T>();
21951        self.addons
21952            .get(&type_id)
21953            .and_then(|item| item.to_any().downcast_ref::<T>())
21954    }
21955
21956    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21957        let type_id = std::any::TypeId::of::<T>();
21958        self.addons
21959            .get_mut(&type_id)
21960            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21961    }
21962
21963    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21964        let text_layout_details = self.text_layout_details(window);
21965        let style = &text_layout_details.editor_style;
21966        let font_id = window.text_system().resolve_font(&style.text.font());
21967        let font_size = style.text.font_size.to_pixels(window.rem_size());
21968        let line_height = style.text.line_height_in_pixels(window.rem_size());
21969        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21970        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21971
21972        CharacterDimensions {
21973            em_width,
21974            em_advance,
21975            line_height,
21976        }
21977    }
21978
21979    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21980        self.load_diff_task.clone()
21981    }
21982
21983    fn read_metadata_from_db(
21984        &mut self,
21985        item_id: u64,
21986        workspace_id: WorkspaceId,
21987        window: &mut Window,
21988        cx: &mut Context<Editor>,
21989    ) {
21990        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21991            && !self.mode.is_minimap()
21992            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21993        {
21994            let buffer_snapshot = OnceCell::new();
21995
21996            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21997                && !folds.is_empty()
21998            {
21999                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22000                self.fold_ranges(
22001                    folds
22002                        .into_iter()
22003                        .map(|(start, end)| {
22004                            snapshot.clip_offset(start, Bias::Left)
22005                                ..snapshot.clip_offset(end, Bias::Right)
22006                        })
22007                        .collect(),
22008                    false,
22009                    window,
22010                    cx,
22011                );
22012            }
22013
22014            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22015                && !selections.is_empty()
22016            {
22017                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22018                // skip adding the initial selection to selection history
22019                self.selection_history.mode = SelectionHistoryMode::Skipping;
22020                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22021                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22022                        snapshot.clip_offset(start, Bias::Left)
22023                            ..snapshot.clip_offset(end, Bias::Right)
22024                    }));
22025                });
22026                self.selection_history.mode = SelectionHistoryMode::Normal;
22027            };
22028        }
22029
22030        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22031    }
22032
22033    fn update_lsp_data(
22034        &mut self,
22035        for_buffer: Option<BufferId>,
22036        window: &mut Window,
22037        cx: &mut Context<'_, Self>,
22038    ) {
22039        self.pull_diagnostics(for_buffer, window, cx);
22040        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22041    }
22042
22043    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22044        if self.ignore_lsp_data() {
22045            return;
22046        }
22047        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22048            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22049        }
22050    }
22051
22052    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22053        if !self.registered_buffers.contains_key(&buffer_id)
22054            && let Some(project) = self.project.as_ref()
22055        {
22056            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22057                project.update(cx, |project, cx| {
22058                    self.registered_buffers.insert(
22059                        buffer_id,
22060                        project.register_buffer_with_language_servers(&buffer, cx),
22061                    );
22062                });
22063            } else {
22064                self.registered_buffers.remove(&buffer_id);
22065            }
22066        }
22067    }
22068
22069    fn ignore_lsp_data(&self) -> bool {
22070        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22071        // skip any LSP updates for it.
22072        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22073    }
22074}
22075
22076fn edit_for_markdown_paste<'a>(
22077    buffer: &MultiBufferSnapshot,
22078    range: Range<usize>,
22079    to_insert: &'a str,
22080    url: Option<url::Url>,
22081) -> (Range<usize>, Cow<'a, str>) {
22082    if url.is_none() {
22083        return (range, Cow::Borrowed(to_insert));
22084    };
22085
22086    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22087
22088    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22089        Cow::Borrowed(to_insert)
22090    } else {
22091        Cow::Owned(format!("[{old_text}]({to_insert})"))
22092    };
22093    (range, new_text)
22094}
22095
22096#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22097pub enum VimFlavor {
22098    Vim,
22099    Helix,
22100}
22101
22102pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22103    if vim_mode_setting::HelixModeSetting::try_get(cx)
22104        .map(|helix_mode| helix_mode.0)
22105        .unwrap_or(false)
22106    {
22107        Some(VimFlavor::Helix)
22108    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22109        .map(|vim_mode| vim_mode.0)
22110        .unwrap_or(false)
22111    {
22112        Some(VimFlavor::Vim)
22113    } else {
22114        None // neither vim nor helix mode
22115    }
22116}
22117
22118fn process_completion_for_edit(
22119    completion: &Completion,
22120    intent: CompletionIntent,
22121    buffer: &Entity<Buffer>,
22122    cursor_position: &text::Anchor,
22123    cx: &mut Context<Editor>,
22124) -> CompletionEdit {
22125    let buffer = buffer.read(cx);
22126    let buffer_snapshot = buffer.snapshot();
22127    let (snippet, new_text) = if completion.is_snippet() {
22128        let mut snippet_source = completion.new_text.clone();
22129        // Workaround for typescript language server issues so that methods don't expand within
22130        // strings and functions with type expressions. The previous point is used because the query
22131        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22132        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22133        let previous_point = if previous_point.column > 0 {
22134            cursor_position.to_previous_offset(&buffer_snapshot)
22135        } else {
22136            cursor_position.to_offset(&buffer_snapshot)
22137        };
22138        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22139            && scope.prefers_label_for_snippet_in_completion()
22140            && let Some(label) = completion.label()
22141            && matches!(
22142                completion.kind(),
22143                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22144            )
22145        {
22146            snippet_source = label;
22147        }
22148        match Snippet::parse(&snippet_source).log_err() {
22149            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22150            None => (None, completion.new_text.clone()),
22151        }
22152    } else {
22153        (None, completion.new_text.clone())
22154    };
22155
22156    let mut range_to_replace = {
22157        let replace_range = &completion.replace_range;
22158        if let CompletionSource::Lsp {
22159            insert_range: Some(insert_range),
22160            ..
22161        } = &completion.source
22162        {
22163            debug_assert_eq!(
22164                insert_range.start, replace_range.start,
22165                "insert_range and replace_range should start at the same position"
22166            );
22167            debug_assert!(
22168                insert_range
22169                    .start
22170                    .cmp(cursor_position, &buffer_snapshot)
22171                    .is_le(),
22172                "insert_range should start before or at cursor position"
22173            );
22174            debug_assert!(
22175                replace_range
22176                    .start
22177                    .cmp(cursor_position, &buffer_snapshot)
22178                    .is_le(),
22179                "replace_range should start before or at cursor position"
22180            );
22181
22182            let should_replace = match intent {
22183                CompletionIntent::CompleteWithInsert => false,
22184                CompletionIntent::CompleteWithReplace => true,
22185                CompletionIntent::Complete | CompletionIntent::Compose => {
22186                    let insert_mode =
22187                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22188                            .completions
22189                            .lsp_insert_mode;
22190                    match insert_mode {
22191                        LspInsertMode::Insert => false,
22192                        LspInsertMode::Replace => true,
22193                        LspInsertMode::ReplaceSubsequence => {
22194                            let mut text_to_replace = buffer.chars_for_range(
22195                                buffer.anchor_before(replace_range.start)
22196                                    ..buffer.anchor_after(replace_range.end),
22197                            );
22198                            let mut current_needle = text_to_replace.next();
22199                            for haystack_ch in completion.label.text.chars() {
22200                                if let Some(needle_ch) = current_needle
22201                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22202                                {
22203                                    current_needle = text_to_replace.next();
22204                                }
22205                            }
22206                            current_needle.is_none()
22207                        }
22208                        LspInsertMode::ReplaceSuffix => {
22209                            if replace_range
22210                                .end
22211                                .cmp(cursor_position, &buffer_snapshot)
22212                                .is_gt()
22213                            {
22214                                let range_after_cursor = *cursor_position..replace_range.end;
22215                                let text_after_cursor = buffer
22216                                    .text_for_range(
22217                                        buffer.anchor_before(range_after_cursor.start)
22218                                            ..buffer.anchor_after(range_after_cursor.end),
22219                                    )
22220                                    .collect::<String>()
22221                                    .to_ascii_lowercase();
22222                                completion
22223                                    .label
22224                                    .text
22225                                    .to_ascii_lowercase()
22226                                    .ends_with(&text_after_cursor)
22227                            } else {
22228                                true
22229                            }
22230                        }
22231                    }
22232                }
22233            };
22234
22235            if should_replace {
22236                replace_range.clone()
22237            } else {
22238                insert_range.clone()
22239            }
22240        } else {
22241            replace_range.clone()
22242        }
22243    };
22244
22245    if range_to_replace
22246        .end
22247        .cmp(cursor_position, &buffer_snapshot)
22248        .is_lt()
22249    {
22250        range_to_replace.end = *cursor_position;
22251    }
22252
22253    CompletionEdit {
22254        new_text,
22255        replace_range: range_to_replace.to_offset(buffer),
22256        snippet,
22257    }
22258}
22259
22260struct CompletionEdit {
22261    new_text: String,
22262    replace_range: Range<usize>,
22263    snippet: Option<Snippet>,
22264}
22265
22266fn insert_extra_newline_brackets(
22267    buffer: &MultiBufferSnapshot,
22268    range: Range<usize>,
22269    language: &language::LanguageScope,
22270) -> bool {
22271    let leading_whitespace_len = buffer
22272        .reversed_chars_at(range.start)
22273        .take_while(|c| c.is_whitespace() && *c != '\n')
22274        .map(|c| c.len_utf8())
22275        .sum::<usize>();
22276    let trailing_whitespace_len = buffer
22277        .chars_at(range.end)
22278        .take_while(|c| c.is_whitespace() && *c != '\n')
22279        .map(|c| c.len_utf8())
22280        .sum::<usize>();
22281    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22282
22283    language.brackets().any(|(pair, enabled)| {
22284        let pair_start = pair.start.trim_end();
22285        let pair_end = pair.end.trim_start();
22286
22287        enabled
22288            && pair.newline
22289            && buffer.contains_str_at(range.end, pair_end)
22290            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22291    })
22292}
22293
22294fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22295    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22296        [(buffer, range, _)] => (*buffer, range.clone()),
22297        _ => return false,
22298    };
22299    let pair = {
22300        let mut result: Option<BracketMatch> = None;
22301
22302        for pair in buffer
22303            .all_bracket_ranges(range.clone())
22304            .filter(move |pair| {
22305                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22306            })
22307        {
22308            let len = pair.close_range.end - pair.open_range.start;
22309
22310            if let Some(existing) = &result {
22311                let existing_len = existing.close_range.end - existing.open_range.start;
22312                if len > existing_len {
22313                    continue;
22314                }
22315            }
22316
22317            result = Some(pair);
22318        }
22319
22320        result
22321    };
22322    let Some(pair) = pair else {
22323        return false;
22324    };
22325    pair.newline_only
22326        && buffer
22327            .chars_for_range(pair.open_range.end..range.start)
22328            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22329            .all(|c| c.is_whitespace() && c != '\n')
22330}
22331
22332fn update_uncommitted_diff_for_buffer(
22333    editor: Entity<Editor>,
22334    project: &Entity<Project>,
22335    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22336    buffer: Entity<MultiBuffer>,
22337    cx: &mut App,
22338) -> Task<()> {
22339    let mut tasks = Vec::new();
22340    project.update(cx, |project, cx| {
22341        for buffer in buffers {
22342            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22343                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22344            }
22345        }
22346    });
22347    cx.spawn(async move |cx| {
22348        let diffs = future::join_all(tasks).await;
22349        if editor
22350            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22351            .unwrap_or(false)
22352        {
22353            return;
22354        }
22355
22356        buffer
22357            .update(cx, |buffer, cx| {
22358                for diff in diffs.into_iter().flatten() {
22359                    buffer.add_diff(diff, cx);
22360                }
22361            })
22362            .ok();
22363    })
22364}
22365
22366fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22367    let tab_size = tab_size.get() as usize;
22368    let mut width = offset;
22369
22370    for ch in text.chars() {
22371        width += if ch == '\t' {
22372            tab_size - (width % tab_size)
22373        } else {
22374            1
22375        };
22376    }
22377
22378    width - offset
22379}
22380
22381#[cfg(test)]
22382mod tests {
22383    use super::*;
22384
22385    #[test]
22386    fn test_string_size_with_expanded_tabs() {
22387        let nz = |val| NonZeroU32::new(val).unwrap();
22388        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22389        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22390        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22391        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22392        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22393        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22394        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22395        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22396    }
22397}
22398
22399/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22400struct WordBreakingTokenizer<'a> {
22401    input: &'a str,
22402}
22403
22404impl<'a> WordBreakingTokenizer<'a> {
22405    fn new(input: &'a str) -> Self {
22406        Self { input }
22407    }
22408}
22409
22410fn is_char_ideographic(ch: char) -> bool {
22411    use unicode_script::Script::*;
22412    use unicode_script::UnicodeScript;
22413    matches!(ch.script(), Han | Tangut | Yi)
22414}
22415
22416fn is_grapheme_ideographic(text: &str) -> bool {
22417    text.chars().any(is_char_ideographic)
22418}
22419
22420fn is_grapheme_whitespace(text: &str) -> bool {
22421    text.chars().any(|x| x.is_whitespace())
22422}
22423
22424fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22425    text.chars()
22426        .next()
22427        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22428}
22429
22430#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22431enum WordBreakToken<'a> {
22432    Word { token: &'a str, grapheme_len: usize },
22433    InlineWhitespace { token: &'a str, grapheme_len: usize },
22434    Newline,
22435}
22436
22437impl<'a> Iterator for WordBreakingTokenizer<'a> {
22438    /// Yields a span, the count of graphemes in the token, and whether it was
22439    /// whitespace. Note that it also breaks at word boundaries.
22440    type Item = WordBreakToken<'a>;
22441
22442    fn next(&mut self) -> Option<Self::Item> {
22443        use unicode_segmentation::UnicodeSegmentation;
22444        if self.input.is_empty() {
22445            return None;
22446        }
22447
22448        let mut iter = self.input.graphemes(true).peekable();
22449        let mut offset = 0;
22450        let mut grapheme_len = 0;
22451        if let Some(first_grapheme) = iter.next() {
22452            let is_newline = first_grapheme == "\n";
22453            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22454            offset += first_grapheme.len();
22455            grapheme_len += 1;
22456            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22457                if let Some(grapheme) = iter.peek().copied()
22458                    && should_stay_with_preceding_ideograph(grapheme)
22459                {
22460                    offset += grapheme.len();
22461                    grapheme_len += 1;
22462                }
22463            } else {
22464                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22465                let mut next_word_bound = words.peek().copied();
22466                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22467                    next_word_bound = words.next();
22468                }
22469                while let Some(grapheme) = iter.peek().copied() {
22470                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22471                        break;
22472                    };
22473                    if is_grapheme_whitespace(grapheme) != is_whitespace
22474                        || (grapheme == "\n") != is_newline
22475                    {
22476                        break;
22477                    };
22478                    offset += grapheme.len();
22479                    grapheme_len += 1;
22480                    iter.next();
22481                }
22482            }
22483            let token = &self.input[..offset];
22484            self.input = &self.input[offset..];
22485            if token == "\n" {
22486                Some(WordBreakToken::Newline)
22487            } else if is_whitespace {
22488                Some(WordBreakToken::InlineWhitespace {
22489                    token,
22490                    grapheme_len,
22491                })
22492            } else {
22493                Some(WordBreakToken::Word {
22494                    token,
22495                    grapheme_len,
22496                })
22497            }
22498        } else {
22499            None
22500        }
22501    }
22502}
22503
22504#[test]
22505fn test_word_breaking_tokenizer() {
22506    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22507        ("", &[]),
22508        ("  ", &[whitespace("  ", 2)]),
22509        ("Ʒ", &[word("Ʒ", 1)]),
22510        ("Ǽ", &[word("Ǽ", 1)]),
22511        ("", &[word("", 1)]),
22512        ("⋑⋑", &[word("⋑⋑", 2)]),
22513        (
22514            "原理,进而",
22515            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22516        ),
22517        (
22518            "hello world",
22519            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22520        ),
22521        (
22522            "hello, world",
22523            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22524        ),
22525        (
22526            "  hello world",
22527            &[
22528                whitespace("  ", 2),
22529                word("hello", 5),
22530                whitespace(" ", 1),
22531                word("world", 5),
22532            ],
22533        ),
22534        (
22535            "这是什么 \n 钢笔",
22536            &[
22537                word("", 1),
22538                word("", 1),
22539                word("", 1),
22540                word("", 1),
22541                whitespace(" ", 1),
22542                newline(),
22543                whitespace(" ", 1),
22544                word("", 1),
22545                word("", 1),
22546            ],
22547        ),
22548        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22549    ];
22550
22551    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22552        WordBreakToken::Word {
22553            token,
22554            grapheme_len,
22555        }
22556    }
22557
22558    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22559        WordBreakToken::InlineWhitespace {
22560            token,
22561            grapheme_len,
22562        }
22563    }
22564
22565    fn newline() -> WordBreakToken<'static> {
22566        WordBreakToken::Newline
22567    }
22568
22569    for (input, result) in tests {
22570        assert_eq!(
22571            WordBreakingTokenizer::new(input)
22572                .collect::<Vec<_>>()
22573                .as_slice(),
22574            *result,
22575        );
22576    }
22577}
22578
22579fn wrap_with_prefix(
22580    first_line_prefix: String,
22581    subsequent_lines_prefix: String,
22582    unwrapped_text: String,
22583    wrap_column: usize,
22584    tab_size: NonZeroU32,
22585    preserve_existing_whitespace: bool,
22586) -> String {
22587    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22588    let subsequent_lines_prefix_len =
22589        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22590    let mut wrapped_text = String::new();
22591    let mut current_line = first_line_prefix;
22592    let mut is_first_line = true;
22593
22594    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22595    let mut current_line_len = first_line_prefix_len;
22596    let mut in_whitespace = false;
22597    for token in tokenizer {
22598        let have_preceding_whitespace = in_whitespace;
22599        match token {
22600            WordBreakToken::Word {
22601                token,
22602                grapheme_len,
22603            } => {
22604                in_whitespace = false;
22605                let current_prefix_len = if is_first_line {
22606                    first_line_prefix_len
22607                } else {
22608                    subsequent_lines_prefix_len
22609                };
22610                if current_line_len + grapheme_len > wrap_column
22611                    && current_line_len != current_prefix_len
22612                {
22613                    wrapped_text.push_str(current_line.trim_end());
22614                    wrapped_text.push('\n');
22615                    is_first_line = false;
22616                    current_line = subsequent_lines_prefix.clone();
22617                    current_line_len = subsequent_lines_prefix_len;
22618                }
22619                current_line.push_str(token);
22620                current_line_len += grapheme_len;
22621            }
22622            WordBreakToken::InlineWhitespace {
22623                mut token,
22624                mut grapheme_len,
22625            } => {
22626                in_whitespace = true;
22627                if have_preceding_whitespace && !preserve_existing_whitespace {
22628                    continue;
22629                }
22630                if !preserve_existing_whitespace {
22631                    // Keep a single whitespace grapheme as-is
22632                    if let Some(first) =
22633                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22634                    {
22635                        token = first;
22636                    } else {
22637                        token = " ";
22638                    }
22639                    grapheme_len = 1;
22640                }
22641                let current_prefix_len = if is_first_line {
22642                    first_line_prefix_len
22643                } else {
22644                    subsequent_lines_prefix_len
22645                };
22646                if current_line_len + grapheme_len > wrap_column {
22647                    wrapped_text.push_str(current_line.trim_end());
22648                    wrapped_text.push('\n');
22649                    is_first_line = false;
22650                    current_line = subsequent_lines_prefix.clone();
22651                    current_line_len = subsequent_lines_prefix_len;
22652                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22653                    current_line.push_str(token);
22654                    current_line_len += grapheme_len;
22655                }
22656            }
22657            WordBreakToken::Newline => {
22658                in_whitespace = true;
22659                let current_prefix_len = if is_first_line {
22660                    first_line_prefix_len
22661                } else {
22662                    subsequent_lines_prefix_len
22663                };
22664                if preserve_existing_whitespace {
22665                    wrapped_text.push_str(current_line.trim_end());
22666                    wrapped_text.push('\n');
22667                    is_first_line = false;
22668                    current_line = subsequent_lines_prefix.clone();
22669                    current_line_len = subsequent_lines_prefix_len;
22670                } else if have_preceding_whitespace {
22671                    continue;
22672                } else if current_line_len + 1 > wrap_column
22673                    && current_line_len != current_prefix_len
22674                {
22675                    wrapped_text.push_str(current_line.trim_end());
22676                    wrapped_text.push('\n');
22677                    is_first_line = false;
22678                    current_line = subsequent_lines_prefix.clone();
22679                    current_line_len = subsequent_lines_prefix_len;
22680                } else if current_line_len != current_prefix_len {
22681                    current_line.push(' ');
22682                    current_line_len += 1;
22683                }
22684            }
22685        }
22686    }
22687
22688    if !current_line.is_empty() {
22689        wrapped_text.push_str(&current_line);
22690    }
22691    wrapped_text
22692}
22693
22694#[test]
22695fn test_wrap_with_prefix() {
22696    assert_eq!(
22697        wrap_with_prefix(
22698            "# ".to_string(),
22699            "# ".to_string(),
22700            "abcdefg".to_string(),
22701            4,
22702            NonZeroU32::new(4).unwrap(),
22703            false,
22704        ),
22705        "# abcdefg"
22706    );
22707    assert_eq!(
22708        wrap_with_prefix(
22709            "".to_string(),
22710            "".to_string(),
22711            "\thello world".to_string(),
22712            8,
22713            NonZeroU32::new(4).unwrap(),
22714            false,
22715        ),
22716        "hello\nworld"
22717    );
22718    assert_eq!(
22719        wrap_with_prefix(
22720            "// ".to_string(),
22721            "// ".to_string(),
22722            "xx \nyy zz aa bb cc".to_string(),
22723            12,
22724            NonZeroU32::new(4).unwrap(),
22725            false,
22726        ),
22727        "// xx yy zz\n// aa bb cc"
22728    );
22729    assert_eq!(
22730        wrap_with_prefix(
22731            String::new(),
22732            String::new(),
22733            "这是什么 \n 钢笔".to_string(),
22734            3,
22735            NonZeroU32::new(4).unwrap(),
22736            false,
22737        ),
22738        "这是什\n么 钢\n"
22739    );
22740    assert_eq!(
22741        wrap_with_prefix(
22742            String::new(),
22743            String::new(),
22744            format!("foo{}bar", '\u{2009}'), // thin space
22745            80,
22746            NonZeroU32::new(4).unwrap(),
22747            false,
22748        ),
22749        format!("foo{}bar", '\u{2009}')
22750    );
22751}
22752
22753pub trait CollaborationHub {
22754    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22755    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22756    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22757}
22758
22759impl CollaborationHub for Entity<Project> {
22760    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22761        self.read(cx).collaborators()
22762    }
22763
22764    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22765        self.read(cx).user_store().read(cx).participant_indices()
22766    }
22767
22768    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22769        let this = self.read(cx);
22770        let user_ids = this.collaborators().values().map(|c| c.user_id);
22771        this.user_store().read(cx).participant_names(user_ids, cx)
22772    }
22773}
22774
22775pub trait SemanticsProvider {
22776    fn hover(
22777        &self,
22778        buffer: &Entity<Buffer>,
22779        position: text::Anchor,
22780        cx: &mut App,
22781    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22782
22783    fn inline_values(
22784        &self,
22785        buffer_handle: Entity<Buffer>,
22786        range: Range<text::Anchor>,
22787        cx: &mut App,
22788    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22789
22790    fn applicable_inlay_chunks(
22791        &self,
22792        buffer: &Entity<Buffer>,
22793        ranges: &[Range<text::Anchor>],
22794        cx: &mut App,
22795    ) -> Vec<Range<BufferRow>>;
22796
22797    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22798
22799    fn inlay_hints(
22800        &self,
22801        invalidate: InvalidationStrategy,
22802        buffer: Entity<Buffer>,
22803        ranges: Vec<Range<text::Anchor>>,
22804        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22805        cx: &mut App,
22806    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22807
22808    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22809
22810    fn document_highlights(
22811        &self,
22812        buffer: &Entity<Buffer>,
22813        position: text::Anchor,
22814        cx: &mut App,
22815    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22816
22817    fn definitions(
22818        &self,
22819        buffer: &Entity<Buffer>,
22820        position: text::Anchor,
22821        kind: GotoDefinitionKind,
22822        cx: &mut App,
22823    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22824
22825    fn range_for_rename(
22826        &self,
22827        buffer: &Entity<Buffer>,
22828        position: text::Anchor,
22829        cx: &mut App,
22830    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22831
22832    fn perform_rename(
22833        &self,
22834        buffer: &Entity<Buffer>,
22835        position: text::Anchor,
22836        new_name: String,
22837        cx: &mut App,
22838    ) -> Option<Task<Result<ProjectTransaction>>>;
22839}
22840
22841pub trait CompletionProvider {
22842    fn completions(
22843        &self,
22844        excerpt_id: ExcerptId,
22845        buffer: &Entity<Buffer>,
22846        buffer_position: text::Anchor,
22847        trigger: CompletionContext,
22848        window: &mut Window,
22849        cx: &mut Context<Editor>,
22850    ) -> Task<Result<Vec<CompletionResponse>>>;
22851
22852    fn resolve_completions(
22853        &self,
22854        _buffer: Entity<Buffer>,
22855        _completion_indices: Vec<usize>,
22856        _completions: Rc<RefCell<Box<[Completion]>>>,
22857        _cx: &mut Context<Editor>,
22858    ) -> Task<Result<bool>> {
22859        Task::ready(Ok(false))
22860    }
22861
22862    fn apply_additional_edits_for_completion(
22863        &self,
22864        _buffer: Entity<Buffer>,
22865        _completions: Rc<RefCell<Box<[Completion]>>>,
22866        _completion_index: usize,
22867        _push_to_history: bool,
22868        _cx: &mut Context<Editor>,
22869    ) -> Task<Result<Option<language::Transaction>>> {
22870        Task::ready(Ok(None))
22871    }
22872
22873    fn is_completion_trigger(
22874        &self,
22875        buffer: &Entity<Buffer>,
22876        position: language::Anchor,
22877        text: &str,
22878        trigger_in_words: bool,
22879        menu_is_open: bool,
22880        cx: &mut Context<Editor>,
22881    ) -> bool;
22882
22883    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22884
22885    fn sort_completions(&self) -> bool {
22886        true
22887    }
22888
22889    fn filter_completions(&self) -> bool {
22890        true
22891    }
22892}
22893
22894pub trait CodeActionProvider {
22895    fn id(&self) -> Arc<str>;
22896
22897    fn code_actions(
22898        &self,
22899        buffer: &Entity<Buffer>,
22900        range: Range<text::Anchor>,
22901        window: &mut Window,
22902        cx: &mut App,
22903    ) -> Task<Result<Vec<CodeAction>>>;
22904
22905    fn apply_code_action(
22906        &self,
22907        buffer_handle: Entity<Buffer>,
22908        action: CodeAction,
22909        excerpt_id: ExcerptId,
22910        push_to_history: bool,
22911        window: &mut Window,
22912        cx: &mut App,
22913    ) -> Task<Result<ProjectTransaction>>;
22914}
22915
22916impl CodeActionProvider for Entity<Project> {
22917    fn id(&self) -> Arc<str> {
22918        "project".into()
22919    }
22920
22921    fn code_actions(
22922        &self,
22923        buffer: &Entity<Buffer>,
22924        range: Range<text::Anchor>,
22925        _window: &mut Window,
22926        cx: &mut App,
22927    ) -> Task<Result<Vec<CodeAction>>> {
22928        self.update(cx, |project, cx| {
22929            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22930            let code_actions = project.code_actions(buffer, range, None, cx);
22931            cx.background_spawn(async move {
22932                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22933                Ok(code_lens_actions
22934                    .context("code lens fetch")?
22935                    .into_iter()
22936                    .flatten()
22937                    .chain(
22938                        code_actions
22939                            .context("code action fetch")?
22940                            .into_iter()
22941                            .flatten(),
22942                    )
22943                    .collect())
22944            })
22945        })
22946    }
22947
22948    fn apply_code_action(
22949        &self,
22950        buffer_handle: Entity<Buffer>,
22951        action: CodeAction,
22952        _excerpt_id: ExcerptId,
22953        push_to_history: bool,
22954        _window: &mut Window,
22955        cx: &mut App,
22956    ) -> Task<Result<ProjectTransaction>> {
22957        self.update(cx, |project, cx| {
22958            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22959        })
22960    }
22961}
22962
22963fn snippet_completions(
22964    project: &Project,
22965    buffer: &Entity<Buffer>,
22966    buffer_position: text::Anchor,
22967    cx: &mut App,
22968) -> Task<Result<CompletionResponse>> {
22969    let languages = buffer.read(cx).languages_at(buffer_position);
22970    let snippet_store = project.snippets().read(cx);
22971
22972    let scopes: Vec<_> = languages
22973        .iter()
22974        .filter_map(|language| {
22975            let language_name = language.lsp_id();
22976            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22977
22978            if snippets.is_empty() {
22979                None
22980            } else {
22981                Some((language.default_scope(), snippets))
22982            }
22983        })
22984        .collect();
22985
22986    if scopes.is_empty() {
22987        return Task::ready(Ok(CompletionResponse {
22988            completions: vec![],
22989            display_options: CompletionDisplayOptions::default(),
22990            is_incomplete: false,
22991        }));
22992    }
22993
22994    let snapshot = buffer.read(cx).text_snapshot();
22995    let executor = cx.background_executor().clone();
22996
22997    cx.background_spawn(async move {
22998        let mut is_incomplete = false;
22999        let mut completions: Vec<Completion> = Vec::new();
23000        for (scope, snippets) in scopes.into_iter() {
23001            let classifier =
23002                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23003
23004            const MAX_WORD_PREFIX_LEN: usize = 128;
23005            let last_word: String = snapshot
23006                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23007                .take(MAX_WORD_PREFIX_LEN)
23008                .take_while(|c| classifier.is_word(*c))
23009                .collect::<String>()
23010                .chars()
23011                .rev()
23012                .collect();
23013
23014            if last_word.is_empty() {
23015                return Ok(CompletionResponse {
23016                    completions: vec![],
23017                    display_options: CompletionDisplayOptions::default(),
23018                    is_incomplete: true,
23019                });
23020            }
23021
23022            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23023            let to_lsp = |point: &text::Anchor| {
23024                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23025                point_to_lsp(end)
23026            };
23027            let lsp_end = to_lsp(&buffer_position);
23028
23029            let candidates = snippets
23030                .iter()
23031                .enumerate()
23032                .flat_map(|(ix, snippet)| {
23033                    snippet
23034                        .prefix
23035                        .iter()
23036                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23037                })
23038                .collect::<Vec<StringMatchCandidate>>();
23039
23040            const MAX_RESULTS: usize = 100;
23041            let mut matches = fuzzy::match_strings(
23042                &candidates,
23043                &last_word,
23044                last_word.chars().any(|c| c.is_uppercase()),
23045                true,
23046                MAX_RESULTS,
23047                &Default::default(),
23048                executor.clone(),
23049            )
23050            .await;
23051
23052            if matches.len() >= MAX_RESULTS {
23053                is_incomplete = true;
23054            }
23055
23056            // Remove all candidates where the query's start does not match the start of any word in the candidate
23057            if let Some(query_start) = last_word.chars().next() {
23058                matches.retain(|string_match| {
23059                    split_words(&string_match.string).any(|word| {
23060                        // Check that the first codepoint of the word as lowercase matches the first
23061                        // codepoint of the query as lowercase
23062                        word.chars()
23063                            .flat_map(|codepoint| codepoint.to_lowercase())
23064                            .zip(query_start.to_lowercase())
23065                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23066                    })
23067                });
23068            }
23069
23070            let matched_strings = matches
23071                .into_iter()
23072                .map(|m| m.string)
23073                .collect::<HashSet<_>>();
23074
23075            completions.extend(snippets.iter().filter_map(|snippet| {
23076                let matching_prefix = snippet
23077                    .prefix
23078                    .iter()
23079                    .find(|prefix| matched_strings.contains(*prefix))?;
23080                let start = as_offset - last_word.len();
23081                let start = snapshot.anchor_before(start);
23082                let range = start..buffer_position;
23083                let lsp_start = to_lsp(&start);
23084                let lsp_range = lsp::Range {
23085                    start: lsp_start,
23086                    end: lsp_end,
23087                };
23088                Some(Completion {
23089                    replace_range: range,
23090                    new_text: snippet.body.clone(),
23091                    source: CompletionSource::Lsp {
23092                        insert_range: None,
23093                        server_id: LanguageServerId(usize::MAX),
23094                        resolved: true,
23095                        lsp_completion: Box::new(lsp::CompletionItem {
23096                            label: snippet.prefix.first().unwrap().clone(),
23097                            kind: Some(CompletionItemKind::SNIPPET),
23098                            label_details: snippet.description.as_ref().map(|description| {
23099                                lsp::CompletionItemLabelDetails {
23100                                    detail: Some(description.clone()),
23101                                    description: None,
23102                                }
23103                            }),
23104                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23105                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23106                                lsp::InsertReplaceEdit {
23107                                    new_text: snippet.body.clone(),
23108                                    insert: lsp_range,
23109                                    replace: lsp_range,
23110                                },
23111                            )),
23112                            filter_text: Some(snippet.body.clone()),
23113                            sort_text: Some(char::MAX.to_string()),
23114                            ..lsp::CompletionItem::default()
23115                        }),
23116                        lsp_defaults: None,
23117                    },
23118                    label: CodeLabel::plain(matching_prefix.clone(), None),
23119                    icon_path: None,
23120                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23121                        single_line: snippet.name.clone().into(),
23122                        plain_text: snippet
23123                            .description
23124                            .clone()
23125                            .map(|description| description.into()),
23126                    }),
23127                    insert_text_mode: None,
23128                    confirm: None,
23129                })
23130            }))
23131        }
23132
23133        Ok(CompletionResponse {
23134            completions,
23135            display_options: CompletionDisplayOptions::default(),
23136            is_incomplete,
23137        })
23138    })
23139}
23140
23141impl CompletionProvider for Entity<Project> {
23142    fn completions(
23143        &self,
23144        _excerpt_id: ExcerptId,
23145        buffer: &Entity<Buffer>,
23146        buffer_position: text::Anchor,
23147        options: CompletionContext,
23148        _window: &mut Window,
23149        cx: &mut Context<Editor>,
23150    ) -> Task<Result<Vec<CompletionResponse>>> {
23151        self.update(cx, |project, cx| {
23152            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23153            let project_completions = project.completions(buffer, buffer_position, options, cx);
23154            cx.background_spawn(async move {
23155                let mut responses = project_completions.await?;
23156                let snippets = snippets.await?;
23157                if !snippets.completions.is_empty() {
23158                    responses.push(snippets);
23159                }
23160                Ok(responses)
23161            })
23162        })
23163    }
23164
23165    fn resolve_completions(
23166        &self,
23167        buffer: Entity<Buffer>,
23168        completion_indices: Vec<usize>,
23169        completions: Rc<RefCell<Box<[Completion]>>>,
23170        cx: &mut Context<Editor>,
23171    ) -> Task<Result<bool>> {
23172        self.update(cx, |project, cx| {
23173            project.lsp_store().update(cx, |lsp_store, cx| {
23174                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23175            })
23176        })
23177    }
23178
23179    fn apply_additional_edits_for_completion(
23180        &self,
23181        buffer: Entity<Buffer>,
23182        completions: Rc<RefCell<Box<[Completion]>>>,
23183        completion_index: usize,
23184        push_to_history: bool,
23185        cx: &mut Context<Editor>,
23186    ) -> Task<Result<Option<language::Transaction>>> {
23187        self.update(cx, |project, cx| {
23188            project.lsp_store().update(cx, |lsp_store, cx| {
23189                lsp_store.apply_additional_edits_for_completion(
23190                    buffer,
23191                    completions,
23192                    completion_index,
23193                    push_to_history,
23194                    cx,
23195                )
23196            })
23197        })
23198    }
23199
23200    fn is_completion_trigger(
23201        &self,
23202        buffer: &Entity<Buffer>,
23203        position: language::Anchor,
23204        text: &str,
23205        trigger_in_words: bool,
23206        menu_is_open: bool,
23207        cx: &mut Context<Editor>,
23208    ) -> bool {
23209        let mut chars = text.chars();
23210        let char = if let Some(char) = chars.next() {
23211            char
23212        } else {
23213            return false;
23214        };
23215        if chars.next().is_some() {
23216            return false;
23217        }
23218
23219        let buffer = buffer.read(cx);
23220        let snapshot = buffer.snapshot();
23221        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23222            return false;
23223        }
23224        let classifier = snapshot
23225            .char_classifier_at(position)
23226            .scope_context(Some(CharScopeContext::Completion));
23227        if trigger_in_words && classifier.is_word(char) {
23228            return true;
23229        }
23230
23231        buffer.completion_triggers().contains(text)
23232    }
23233}
23234
23235impl SemanticsProvider for Entity<Project> {
23236    fn hover(
23237        &self,
23238        buffer: &Entity<Buffer>,
23239        position: text::Anchor,
23240        cx: &mut App,
23241    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23242        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23243    }
23244
23245    fn document_highlights(
23246        &self,
23247        buffer: &Entity<Buffer>,
23248        position: text::Anchor,
23249        cx: &mut App,
23250    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23251        Some(self.update(cx, |project, cx| {
23252            project.document_highlights(buffer, position, cx)
23253        }))
23254    }
23255
23256    fn definitions(
23257        &self,
23258        buffer: &Entity<Buffer>,
23259        position: text::Anchor,
23260        kind: GotoDefinitionKind,
23261        cx: &mut App,
23262    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23263        Some(self.update(cx, |project, cx| match kind {
23264            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23265            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23266            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23267            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23268        }))
23269    }
23270
23271    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23272        self.update(cx, |project, cx| {
23273            if project
23274                .active_debug_session(cx)
23275                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23276            {
23277                return true;
23278            }
23279
23280            buffer.update(cx, |buffer, cx| {
23281                project.any_language_server_supports_inlay_hints(buffer, cx)
23282            })
23283        })
23284    }
23285
23286    fn inline_values(
23287        &self,
23288        buffer_handle: Entity<Buffer>,
23289        range: Range<text::Anchor>,
23290        cx: &mut App,
23291    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23292        self.update(cx, |project, cx| {
23293            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23294
23295            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23296        })
23297    }
23298
23299    fn applicable_inlay_chunks(
23300        &self,
23301        buffer: &Entity<Buffer>,
23302        ranges: &[Range<text::Anchor>],
23303        cx: &mut App,
23304    ) -> Vec<Range<BufferRow>> {
23305        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23306            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23307        })
23308    }
23309
23310    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23311        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23312            lsp_store.invalidate_inlay_hints(for_buffers)
23313        });
23314    }
23315
23316    fn inlay_hints(
23317        &self,
23318        invalidate: InvalidationStrategy,
23319        buffer: Entity<Buffer>,
23320        ranges: Vec<Range<text::Anchor>>,
23321        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23322        cx: &mut App,
23323    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23324        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23325            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23326        }))
23327    }
23328
23329    fn range_for_rename(
23330        &self,
23331        buffer: &Entity<Buffer>,
23332        position: text::Anchor,
23333        cx: &mut App,
23334    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23335        Some(self.update(cx, |project, cx| {
23336            let buffer = buffer.clone();
23337            let task = project.prepare_rename(buffer.clone(), position, cx);
23338            cx.spawn(async move |_, cx| {
23339                Ok(match task.await? {
23340                    PrepareRenameResponse::Success(range) => Some(range),
23341                    PrepareRenameResponse::InvalidPosition => None,
23342                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23343                        // Fallback on using TreeSitter info to determine identifier range
23344                        buffer.read_with(cx, |buffer, _| {
23345                            let snapshot = buffer.snapshot();
23346                            let (range, kind) = snapshot.surrounding_word(position, None);
23347                            if kind != Some(CharKind::Word) {
23348                                return None;
23349                            }
23350                            Some(
23351                                snapshot.anchor_before(range.start)
23352                                    ..snapshot.anchor_after(range.end),
23353                            )
23354                        })?
23355                    }
23356                })
23357            })
23358        }))
23359    }
23360
23361    fn perform_rename(
23362        &self,
23363        buffer: &Entity<Buffer>,
23364        position: text::Anchor,
23365        new_name: String,
23366        cx: &mut App,
23367    ) -> Option<Task<Result<ProjectTransaction>>> {
23368        Some(self.update(cx, |project, cx| {
23369            project.perform_rename(buffer.clone(), position, new_name, cx)
23370        }))
23371    }
23372}
23373
23374fn consume_contiguous_rows(
23375    contiguous_row_selections: &mut Vec<Selection<Point>>,
23376    selection: &Selection<Point>,
23377    display_map: &DisplaySnapshot,
23378    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23379) -> (MultiBufferRow, MultiBufferRow) {
23380    contiguous_row_selections.push(selection.clone());
23381    let start_row = starting_row(selection, display_map);
23382    let mut end_row = ending_row(selection, display_map);
23383
23384    while let Some(next_selection) = selections.peek() {
23385        if next_selection.start.row <= end_row.0 {
23386            end_row = ending_row(next_selection, display_map);
23387            contiguous_row_selections.push(selections.next().unwrap().clone());
23388        } else {
23389            break;
23390        }
23391    }
23392    (start_row, end_row)
23393}
23394
23395fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23396    if selection.start.column > 0 {
23397        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23398    } else {
23399        MultiBufferRow(selection.start.row)
23400    }
23401}
23402
23403fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23404    if next_selection.end.column > 0 || next_selection.is_empty() {
23405        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23406    } else {
23407        MultiBufferRow(next_selection.end.row)
23408    }
23409}
23410
23411impl EditorSnapshot {
23412    pub fn remote_selections_in_range<'a>(
23413        &'a self,
23414        range: &'a Range<Anchor>,
23415        collaboration_hub: &dyn CollaborationHub,
23416        cx: &'a App,
23417    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23418        let participant_names = collaboration_hub.user_names(cx);
23419        let participant_indices = collaboration_hub.user_participant_indices(cx);
23420        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23421        let collaborators_by_replica_id = collaborators_by_peer_id
23422            .values()
23423            .map(|collaborator| (collaborator.replica_id, collaborator))
23424            .collect::<HashMap<_, _>>();
23425        self.buffer_snapshot()
23426            .selections_in_range(range, false)
23427            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23428                if replica_id == ReplicaId::AGENT {
23429                    Some(RemoteSelection {
23430                        replica_id,
23431                        selection,
23432                        cursor_shape,
23433                        line_mode,
23434                        collaborator_id: CollaboratorId::Agent,
23435                        user_name: Some("Agent".into()),
23436                        color: cx.theme().players().agent(),
23437                    })
23438                } else {
23439                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23440                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23441                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23442                    Some(RemoteSelection {
23443                        replica_id,
23444                        selection,
23445                        cursor_shape,
23446                        line_mode,
23447                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23448                        user_name,
23449                        color: if let Some(index) = participant_index {
23450                            cx.theme().players().color_for_participant(index.0)
23451                        } else {
23452                            cx.theme().players().absent()
23453                        },
23454                    })
23455                }
23456            })
23457    }
23458
23459    pub fn hunks_for_ranges(
23460        &self,
23461        ranges: impl IntoIterator<Item = Range<Point>>,
23462    ) -> Vec<MultiBufferDiffHunk> {
23463        let mut hunks = Vec::new();
23464        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23465            HashMap::default();
23466        for query_range in ranges {
23467            let query_rows =
23468                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23469            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23470                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23471            ) {
23472                // Include deleted hunks that are adjacent to the query range, because
23473                // otherwise they would be missed.
23474                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23475                if hunk.status().is_deleted() {
23476                    intersects_range |= hunk.row_range.start == query_rows.end;
23477                    intersects_range |= hunk.row_range.end == query_rows.start;
23478                }
23479                if intersects_range {
23480                    if !processed_buffer_rows
23481                        .entry(hunk.buffer_id)
23482                        .or_default()
23483                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23484                    {
23485                        continue;
23486                    }
23487                    hunks.push(hunk);
23488                }
23489            }
23490        }
23491
23492        hunks
23493    }
23494
23495    fn display_diff_hunks_for_rows<'a>(
23496        &'a self,
23497        display_rows: Range<DisplayRow>,
23498        folded_buffers: &'a HashSet<BufferId>,
23499    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23500        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23501        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23502
23503        self.buffer_snapshot()
23504            .diff_hunks_in_range(buffer_start..buffer_end)
23505            .filter_map(|hunk| {
23506                if folded_buffers.contains(&hunk.buffer_id) {
23507                    return None;
23508                }
23509
23510                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23511                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23512
23513                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23514                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23515
23516                let display_hunk = if hunk_display_start.column() != 0 {
23517                    DisplayDiffHunk::Folded {
23518                        display_row: hunk_display_start.row(),
23519                    }
23520                } else {
23521                    let mut end_row = hunk_display_end.row();
23522                    if hunk_display_end.column() > 0 {
23523                        end_row.0 += 1;
23524                    }
23525                    let is_created_file = hunk.is_created_file();
23526                    DisplayDiffHunk::Unfolded {
23527                        status: hunk.status(),
23528                        diff_base_byte_range: hunk.diff_base_byte_range,
23529                        display_row_range: hunk_display_start.row()..end_row,
23530                        multi_buffer_range: Anchor::range_in_buffer(
23531                            hunk.excerpt_id,
23532                            hunk.buffer_id,
23533                            hunk.buffer_range,
23534                        ),
23535                        is_created_file,
23536                    }
23537                };
23538
23539                Some(display_hunk)
23540            })
23541    }
23542
23543    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23544        self.display_snapshot
23545            .buffer_snapshot()
23546            .language_at(position)
23547    }
23548
23549    pub fn is_focused(&self) -> bool {
23550        self.is_focused
23551    }
23552
23553    pub fn placeholder_text(&self) -> Option<String> {
23554        self.placeholder_display_snapshot
23555            .as_ref()
23556            .map(|display_map| display_map.text())
23557    }
23558
23559    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23560        self.scroll_anchor.scroll_position(&self.display_snapshot)
23561    }
23562
23563    fn gutter_dimensions(
23564        &self,
23565        font_id: FontId,
23566        font_size: Pixels,
23567        max_line_number_width: Pixels,
23568        cx: &App,
23569    ) -> Option<GutterDimensions> {
23570        if !self.show_gutter {
23571            return None;
23572        }
23573
23574        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23575        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23576
23577        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23578            matches!(
23579                ProjectSettings::get_global(cx).git.git_gutter,
23580                GitGutterSetting::TrackedFiles
23581            )
23582        });
23583        let gutter_settings = EditorSettings::get_global(cx).gutter;
23584        let show_line_numbers = self
23585            .show_line_numbers
23586            .unwrap_or(gutter_settings.line_numbers);
23587        let line_gutter_width = if show_line_numbers {
23588            // Avoid flicker-like gutter resizes when the line number gains another digit by
23589            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23590            let min_width_for_number_on_gutter =
23591                ch_advance * gutter_settings.min_line_number_digits as f32;
23592            max_line_number_width.max(min_width_for_number_on_gutter)
23593        } else {
23594            0.0.into()
23595        };
23596
23597        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23598        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23599
23600        let git_blame_entries_width =
23601            self.git_blame_gutter_max_author_length
23602                .map(|max_author_length| {
23603                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23604                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23605
23606                    /// The number of characters to dedicate to gaps and margins.
23607                    const SPACING_WIDTH: usize = 4;
23608
23609                    let max_char_count = max_author_length.min(renderer.max_author_length())
23610                        + ::git::SHORT_SHA_LENGTH
23611                        + MAX_RELATIVE_TIMESTAMP.len()
23612                        + SPACING_WIDTH;
23613
23614                    ch_advance * max_char_count
23615                });
23616
23617        let is_singleton = self.buffer_snapshot().is_singleton();
23618
23619        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23620        left_padding += if !is_singleton {
23621            ch_width * 4.0
23622        } else if show_runnables || show_breakpoints {
23623            ch_width * 3.0
23624        } else if show_git_gutter && show_line_numbers {
23625            ch_width * 2.0
23626        } else if show_git_gutter || show_line_numbers {
23627            ch_width
23628        } else {
23629            px(0.)
23630        };
23631
23632        let shows_folds = is_singleton && gutter_settings.folds;
23633
23634        let right_padding = if shows_folds && show_line_numbers {
23635            ch_width * 4.0
23636        } else if shows_folds || (!is_singleton && show_line_numbers) {
23637            ch_width * 3.0
23638        } else if show_line_numbers {
23639            ch_width
23640        } else {
23641            px(0.)
23642        };
23643
23644        Some(GutterDimensions {
23645            left_padding,
23646            right_padding,
23647            width: line_gutter_width + left_padding + right_padding,
23648            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23649            git_blame_entries_width,
23650        })
23651    }
23652
23653    pub fn render_crease_toggle(
23654        &self,
23655        buffer_row: MultiBufferRow,
23656        row_contains_cursor: bool,
23657        editor: Entity<Editor>,
23658        window: &mut Window,
23659        cx: &mut App,
23660    ) -> Option<AnyElement> {
23661        let folded = self.is_line_folded(buffer_row);
23662        let mut is_foldable = false;
23663
23664        if let Some(crease) = self
23665            .crease_snapshot
23666            .query_row(buffer_row, self.buffer_snapshot())
23667        {
23668            is_foldable = true;
23669            match crease {
23670                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23671                    if let Some(render_toggle) = render_toggle {
23672                        let toggle_callback =
23673                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23674                                if folded {
23675                                    editor.update(cx, |editor, cx| {
23676                                        editor.fold_at(buffer_row, window, cx)
23677                                    });
23678                                } else {
23679                                    editor.update(cx, |editor, cx| {
23680                                        editor.unfold_at(buffer_row, window, cx)
23681                                    });
23682                                }
23683                            });
23684                        return Some((render_toggle)(
23685                            buffer_row,
23686                            folded,
23687                            toggle_callback,
23688                            window,
23689                            cx,
23690                        ));
23691                    }
23692                }
23693            }
23694        }
23695
23696        is_foldable |= self.starts_indent(buffer_row);
23697
23698        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23699            Some(
23700                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23701                    .toggle_state(folded)
23702                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23703                        if folded {
23704                            this.unfold_at(buffer_row, window, cx);
23705                        } else {
23706                            this.fold_at(buffer_row, window, cx);
23707                        }
23708                    }))
23709                    .into_any_element(),
23710            )
23711        } else {
23712            None
23713        }
23714    }
23715
23716    pub fn render_crease_trailer(
23717        &self,
23718        buffer_row: MultiBufferRow,
23719        window: &mut Window,
23720        cx: &mut App,
23721    ) -> Option<AnyElement> {
23722        let folded = self.is_line_folded(buffer_row);
23723        if let Crease::Inline { render_trailer, .. } = self
23724            .crease_snapshot
23725            .query_row(buffer_row, self.buffer_snapshot())?
23726        {
23727            let render_trailer = render_trailer.as_ref()?;
23728            Some(render_trailer(buffer_row, folded, window, cx))
23729        } else {
23730            None
23731        }
23732    }
23733}
23734
23735impl Deref for EditorSnapshot {
23736    type Target = DisplaySnapshot;
23737
23738    fn deref(&self) -> &Self::Target {
23739        &self.display_snapshot
23740    }
23741}
23742
23743#[derive(Clone, Debug, PartialEq, Eq)]
23744pub enum EditorEvent {
23745    InputIgnored {
23746        text: Arc<str>,
23747    },
23748    InputHandled {
23749        utf16_range_to_replace: Option<Range<isize>>,
23750        text: Arc<str>,
23751    },
23752    ExcerptsAdded {
23753        buffer: Entity<Buffer>,
23754        predecessor: ExcerptId,
23755        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23756    },
23757    ExcerptsRemoved {
23758        ids: Vec<ExcerptId>,
23759        removed_buffer_ids: Vec<BufferId>,
23760    },
23761    BufferFoldToggled {
23762        ids: Vec<ExcerptId>,
23763        folded: bool,
23764    },
23765    ExcerptsEdited {
23766        ids: Vec<ExcerptId>,
23767    },
23768    ExcerptsExpanded {
23769        ids: Vec<ExcerptId>,
23770    },
23771    BufferEdited,
23772    Edited {
23773        transaction_id: clock::Lamport,
23774    },
23775    Reparsed(BufferId),
23776    Focused,
23777    FocusedIn,
23778    Blurred,
23779    DirtyChanged,
23780    Saved,
23781    TitleChanged,
23782    SelectionsChanged {
23783        local: bool,
23784    },
23785    ScrollPositionChanged {
23786        local: bool,
23787        autoscroll: bool,
23788    },
23789    TransactionUndone {
23790        transaction_id: clock::Lamport,
23791    },
23792    TransactionBegun {
23793        transaction_id: clock::Lamport,
23794    },
23795    CursorShapeChanged,
23796    BreadcrumbsChanged,
23797    PushedToNavHistory {
23798        anchor: Anchor,
23799        is_deactivate: bool,
23800    },
23801}
23802
23803impl EventEmitter<EditorEvent> for Editor {}
23804
23805impl Focusable for Editor {
23806    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23807        self.focus_handle.clone()
23808    }
23809}
23810
23811impl Render for Editor {
23812    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23813        let settings = ThemeSettings::get_global(cx);
23814
23815        let mut text_style = match self.mode {
23816            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23817                color: cx.theme().colors().editor_foreground,
23818                font_family: settings.ui_font.family.clone(),
23819                font_features: settings.ui_font.features.clone(),
23820                font_fallbacks: settings.ui_font.fallbacks.clone(),
23821                font_size: rems(0.875).into(),
23822                font_weight: settings.ui_font.weight,
23823                line_height: relative(settings.buffer_line_height.value()),
23824                ..Default::default()
23825            },
23826            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23827                color: cx.theme().colors().editor_foreground,
23828                font_family: settings.buffer_font.family.clone(),
23829                font_features: settings.buffer_font.features.clone(),
23830                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23831                font_size: settings.buffer_font_size(cx).into(),
23832                font_weight: settings.buffer_font.weight,
23833                line_height: relative(settings.buffer_line_height.value()),
23834                ..Default::default()
23835            },
23836        };
23837        if let Some(text_style_refinement) = &self.text_style_refinement {
23838            text_style.refine(text_style_refinement)
23839        }
23840
23841        let background = match self.mode {
23842            EditorMode::SingleLine => cx.theme().system().transparent,
23843            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23844            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23845            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23846        };
23847
23848        EditorElement::new(
23849            &cx.entity(),
23850            EditorStyle {
23851                background,
23852                border: cx.theme().colors().border,
23853                local_player: cx.theme().players().local(),
23854                text: text_style,
23855                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23856                syntax: cx.theme().syntax().clone(),
23857                status: cx.theme().status().clone(),
23858                inlay_hints_style: make_inlay_hints_style(cx),
23859                edit_prediction_styles: make_suggestion_styles(cx),
23860                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23861                show_underlines: self.diagnostics_enabled(),
23862            },
23863        )
23864    }
23865}
23866
23867impl EntityInputHandler for Editor {
23868    fn text_for_range(
23869        &mut self,
23870        range_utf16: Range<usize>,
23871        adjusted_range: &mut Option<Range<usize>>,
23872        _: &mut Window,
23873        cx: &mut Context<Self>,
23874    ) -> Option<String> {
23875        let snapshot = self.buffer.read(cx).read(cx);
23876        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23877        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23878        if (start.0..end.0) != range_utf16 {
23879            adjusted_range.replace(start.0..end.0);
23880        }
23881        Some(snapshot.text_for_range(start..end).collect())
23882    }
23883
23884    fn selected_text_range(
23885        &mut self,
23886        ignore_disabled_input: bool,
23887        _: &mut Window,
23888        cx: &mut Context<Self>,
23889    ) -> Option<UTF16Selection> {
23890        // Prevent the IME menu from appearing when holding down an alphabetic key
23891        // while input is disabled.
23892        if !ignore_disabled_input && !self.input_enabled {
23893            return None;
23894        }
23895
23896        let selection = self
23897            .selections
23898            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23899        let range = selection.range();
23900
23901        Some(UTF16Selection {
23902            range: range.start.0..range.end.0,
23903            reversed: selection.reversed,
23904        })
23905    }
23906
23907    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23908        let snapshot = self.buffer.read(cx).read(cx);
23909        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23910        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23911    }
23912
23913    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23914        self.clear_highlights::<InputComposition>(cx);
23915        self.ime_transaction.take();
23916    }
23917
23918    fn replace_text_in_range(
23919        &mut self,
23920        range_utf16: Option<Range<usize>>,
23921        text: &str,
23922        window: &mut Window,
23923        cx: &mut Context<Self>,
23924    ) {
23925        if !self.input_enabled {
23926            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23927            return;
23928        }
23929
23930        self.transact(window, cx, |this, window, cx| {
23931            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23932                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23933                Some(this.selection_replacement_ranges(range_utf16, cx))
23934            } else {
23935                this.marked_text_ranges(cx)
23936            };
23937
23938            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23939                let newest_selection_id = this.selections.newest_anchor().id;
23940                this.selections
23941                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23942                    .iter()
23943                    .zip(ranges_to_replace.iter())
23944                    .find_map(|(selection, range)| {
23945                        if selection.id == newest_selection_id {
23946                            Some(
23947                                (range.start.0 as isize - selection.head().0 as isize)
23948                                    ..(range.end.0 as isize - selection.head().0 as isize),
23949                            )
23950                        } else {
23951                            None
23952                        }
23953                    })
23954            });
23955
23956            cx.emit(EditorEvent::InputHandled {
23957                utf16_range_to_replace: range_to_replace,
23958                text: text.into(),
23959            });
23960
23961            if let Some(new_selected_ranges) = new_selected_ranges {
23962                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23963                    selections.select_ranges(new_selected_ranges)
23964                });
23965                this.backspace(&Default::default(), window, cx);
23966            }
23967
23968            this.handle_input(text, window, cx);
23969        });
23970
23971        if let Some(transaction) = self.ime_transaction {
23972            self.buffer.update(cx, |buffer, cx| {
23973                buffer.group_until_transaction(transaction, cx);
23974            });
23975        }
23976
23977        self.unmark_text(window, cx);
23978    }
23979
23980    fn replace_and_mark_text_in_range(
23981        &mut self,
23982        range_utf16: Option<Range<usize>>,
23983        text: &str,
23984        new_selected_range_utf16: Option<Range<usize>>,
23985        window: &mut Window,
23986        cx: &mut Context<Self>,
23987    ) {
23988        if !self.input_enabled {
23989            return;
23990        }
23991
23992        let transaction = self.transact(window, cx, |this, window, cx| {
23993            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23994                let snapshot = this.buffer.read(cx).read(cx);
23995                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23996                    for marked_range in &mut marked_ranges {
23997                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23998                        marked_range.start.0 += relative_range_utf16.start;
23999                        marked_range.start =
24000                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24001                        marked_range.end =
24002                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24003                    }
24004                }
24005                Some(marked_ranges)
24006            } else if let Some(range_utf16) = range_utf16 {
24007                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24008                Some(this.selection_replacement_ranges(range_utf16, cx))
24009            } else {
24010                None
24011            };
24012
24013            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24014                let newest_selection_id = this.selections.newest_anchor().id;
24015                this.selections
24016                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24017                    .iter()
24018                    .zip(ranges_to_replace.iter())
24019                    .find_map(|(selection, range)| {
24020                        if selection.id == newest_selection_id {
24021                            Some(
24022                                (range.start.0 as isize - selection.head().0 as isize)
24023                                    ..(range.end.0 as isize - selection.head().0 as isize),
24024                            )
24025                        } else {
24026                            None
24027                        }
24028                    })
24029            });
24030
24031            cx.emit(EditorEvent::InputHandled {
24032                utf16_range_to_replace: range_to_replace,
24033                text: text.into(),
24034            });
24035
24036            if let Some(ranges) = ranges_to_replace {
24037                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24038                    s.select_ranges(ranges)
24039                });
24040            }
24041
24042            let marked_ranges = {
24043                let snapshot = this.buffer.read(cx).read(cx);
24044                this.selections
24045                    .disjoint_anchors_arc()
24046                    .iter()
24047                    .map(|selection| {
24048                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24049                    })
24050                    .collect::<Vec<_>>()
24051            };
24052
24053            if text.is_empty() {
24054                this.unmark_text(window, cx);
24055            } else {
24056                this.highlight_text::<InputComposition>(
24057                    marked_ranges.clone(),
24058                    HighlightStyle {
24059                        underline: Some(UnderlineStyle {
24060                            thickness: px(1.),
24061                            color: None,
24062                            wavy: false,
24063                        }),
24064                        ..Default::default()
24065                    },
24066                    cx,
24067                );
24068            }
24069
24070            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24071            let use_autoclose = this.use_autoclose;
24072            let use_auto_surround = this.use_auto_surround;
24073            this.set_use_autoclose(false);
24074            this.set_use_auto_surround(false);
24075            this.handle_input(text, window, cx);
24076            this.set_use_autoclose(use_autoclose);
24077            this.set_use_auto_surround(use_auto_surround);
24078
24079            if let Some(new_selected_range) = new_selected_range_utf16 {
24080                let snapshot = this.buffer.read(cx).read(cx);
24081                let new_selected_ranges = marked_ranges
24082                    .into_iter()
24083                    .map(|marked_range| {
24084                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24085                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24086                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24087                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24088                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24089                    })
24090                    .collect::<Vec<_>>();
24091
24092                drop(snapshot);
24093                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24094                    selections.select_ranges(new_selected_ranges)
24095                });
24096            }
24097        });
24098
24099        self.ime_transaction = self.ime_transaction.or(transaction);
24100        if let Some(transaction) = self.ime_transaction {
24101            self.buffer.update(cx, |buffer, cx| {
24102                buffer.group_until_transaction(transaction, cx);
24103            });
24104        }
24105
24106        if self.text_highlights::<InputComposition>(cx).is_none() {
24107            self.ime_transaction.take();
24108        }
24109    }
24110
24111    fn bounds_for_range(
24112        &mut self,
24113        range_utf16: Range<usize>,
24114        element_bounds: gpui::Bounds<Pixels>,
24115        window: &mut Window,
24116        cx: &mut Context<Self>,
24117    ) -> Option<gpui::Bounds<Pixels>> {
24118        let text_layout_details = self.text_layout_details(window);
24119        let CharacterDimensions {
24120            em_width,
24121            em_advance,
24122            line_height,
24123        } = self.character_dimensions(window);
24124
24125        let snapshot = self.snapshot(window, cx);
24126        let scroll_position = snapshot.scroll_position();
24127        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24128
24129        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24130        let x = Pixels::from(
24131            ScrollOffset::from(
24132                snapshot.x_for_display_point(start, &text_layout_details)
24133                    + self.gutter_dimensions.full_width(),
24134            ) - scroll_left,
24135        );
24136        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24137
24138        Some(Bounds {
24139            origin: element_bounds.origin + point(x, y),
24140            size: size(em_width, line_height),
24141        })
24142    }
24143
24144    fn character_index_for_point(
24145        &mut self,
24146        point: gpui::Point<Pixels>,
24147        _window: &mut Window,
24148        _cx: &mut Context<Self>,
24149    ) -> Option<usize> {
24150        let position_map = self.last_position_map.as_ref()?;
24151        if !position_map.text_hitbox.contains(&point) {
24152            return None;
24153        }
24154        let display_point = position_map.point_for_position(point).previous_valid;
24155        let anchor = position_map
24156            .snapshot
24157            .display_point_to_anchor(display_point, Bias::Left);
24158        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24159        Some(utf16_offset.0)
24160    }
24161}
24162
24163trait SelectionExt {
24164    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24165    fn spanned_rows(
24166        &self,
24167        include_end_if_at_line_start: bool,
24168        map: &DisplaySnapshot,
24169    ) -> Range<MultiBufferRow>;
24170}
24171
24172impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24173    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24174        let start = self
24175            .start
24176            .to_point(map.buffer_snapshot())
24177            .to_display_point(map);
24178        let end = self
24179            .end
24180            .to_point(map.buffer_snapshot())
24181            .to_display_point(map);
24182        if self.reversed {
24183            end..start
24184        } else {
24185            start..end
24186        }
24187    }
24188
24189    fn spanned_rows(
24190        &self,
24191        include_end_if_at_line_start: bool,
24192        map: &DisplaySnapshot,
24193    ) -> Range<MultiBufferRow> {
24194        let start = self.start.to_point(map.buffer_snapshot());
24195        let mut end = self.end.to_point(map.buffer_snapshot());
24196        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24197            end.row -= 1;
24198        }
24199
24200        let buffer_start = map.prev_line_boundary(start).0;
24201        let buffer_end = map.next_line_boundary(end).0;
24202        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24203    }
24204}
24205
24206impl<T: InvalidationRegion> InvalidationStack<T> {
24207    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24208    where
24209        S: Clone + ToOffset,
24210    {
24211        while let Some(region) = self.last() {
24212            let all_selections_inside_invalidation_ranges =
24213                if selections.len() == region.ranges().len() {
24214                    selections
24215                        .iter()
24216                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24217                        .all(|(selection, invalidation_range)| {
24218                            let head = selection.head().to_offset(buffer);
24219                            invalidation_range.start <= head && invalidation_range.end >= head
24220                        })
24221                } else {
24222                    false
24223                };
24224
24225            if all_selections_inside_invalidation_ranges {
24226                break;
24227            } else {
24228                self.pop();
24229            }
24230        }
24231    }
24232}
24233
24234impl<T> Default for InvalidationStack<T> {
24235    fn default() -> Self {
24236        Self(Default::default())
24237    }
24238}
24239
24240impl<T> Deref for InvalidationStack<T> {
24241    type Target = Vec<T>;
24242
24243    fn deref(&self) -> &Self::Target {
24244        &self.0
24245    }
24246}
24247
24248impl<T> DerefMut for InvalidationStack<T> {
24249    fn deref_mut(&mut self) -> &mut Self::Target {
24250        &mut self.0
24251    }
24252}
24253
24254impl InvalidationRegion for SnippetState {
24255    fn ranges(&self) -> &[Range<Anchor>] {
24256        &self.ranges[self.active_index]
24257    }
24258}
24259
24260fn edit_prediction_edit_text(
24261    current_snapshot: &BufferSnapshot,
24262    edits: &[(Range<Anchor>, String)],
24263    edit_preview: &EditPreview,
24264    include_deletions: bool,
24265    cx: &App,
24266) -> HighlightedText {
24267    let edits = edits
24268        .iter()
24269        .map(|(anchor, text)| {
24270            (
24271                anchor.start.text_anchor..anchor.end.text_anchor,
24272                text.clone(),
24273            )
24274        })
24275        .collect::<Vec<_>>();
24276
24277    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24278}
24279
24280fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24281    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24282    // Just show the raw edit text with basic styling
24283    let mut text = String::new();
24284    let mut highlights = Vec::new();
24285
24286    let insertion_highlight_style = HighlightStyle {
24287        color: Some(cx.theme().colors().text),
24288        ..Default::default()
24289    };
24290
24291    for (_, edit_text) in edits {
24292        let start_offset = text.len();
24293        text.push_str(edit_text);
24294        let end_offset = text.len();
24295
24296        if start_offset < end_offset {
24297            highlights.push((start_offset..end_offset, insertion_highlight_style));
24298        }
24299    }
24300
24301    HighlightedText {
24302        text: text.into(),
24303        highlights,
24304    }
24305}
24306
24307pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24308    match severity {
24309        lsp::DiagnosticSeverity::ERROR => colors.error,
24310        lsp::DiagnosticSeverity::WARNING => colors.warning,
24311        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24312        lsp::DiagnosticSeverity::HINT => colors.info,
24313        _ => colors.ignored,
24314    }
24315}
24316
24317pub fn styled_runs_for_code_label<'a>(
24318    label: &'a CodeLabel,
24319    syntax_theme: &'a theme::SyntaxTheme,
24320) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24321    let fade_out = HighlightStyle {
24322        fade_out: Some(0.35),
24323        ..Default::default()
24324    };
24325
24326    let mut prev_end = label.filter_range.end;
24327    label
24328        .runs
24329        .iter()
24330        .enumerate()
24331        .flat_map(move |(ix, (range, highlight_id))| {
24332            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24333                style
24334            } else {
24335                return Default::default();
24336            };
24337            let muted_style = style.highlight(fade_out);
24338
24339            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24340            if range.start >= label.filter_range.end {
24341                if range.start > prev_end {
24342                    runs.push((prev_end..range.start, fade_out));
24343                }
24344                runs.push((range.clone(), muted_style));
24345            } else if range.end <= label.filter_range.end {
24346                runs.push((range.clone(), style));
24347            } else {
24348                runs.push((range.start..label.filter_range.end, style));
24349                runs.push((label.filter_range.end..range.end, muted_style));
24350            }
24351            prev_end = cmp::max(prev_end, range.end);
24352
24353            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24354                runs.push((prev_end..label.text.len(), fade_out));
24355            }
24356
24357            runs
24358        })
24359}
24360
24361pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24362    let mut prev_index = 0;
24363    let mut prev_codepoint: Option<char> = None;
24364    text.char_indices()
24365        .chain([(text.len(), '\0')])
24366        .filter_map(move |(index, codepoint)| {
24367            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24368            let is_boundary = index == text.len()
24369                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24370                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24371            if is_boundary {
24372                let chunk = &text[prev_index..index];
24373                prev_index = index;
24374                Some(chunk)
24375            } else {
24376                None
24377            }
24378        })
24379}
24380
24381pub trait RangeToAnchorExt: Sized {
24382    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24383
24384    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24385        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24386        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24387    }
24388}
24389
24390impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24391    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24392        let start_offset = self.start.to_offset(snapshot);
24393        let end_offset = self.end.to_offset(snapshot);
24394        if start_offset == end_offset {
24395            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24396        } else {
24397            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24398        }
24399    }
24400}
24401
24402pub trait RowExt {
24403    fn as_f64(&self) -> f64;
24404
24405    fn next_row(&self) -> Self;
24406
24407    fn previous_row(&self) -> Self;
24408
24409    fn minus(&self, other: Self) -> u32;
24410}
24411
24412impl RowExt for DisplayRow {
24413    fn as_f64(&self) -> f64 {
24414        self.0 as _
24415    }
24416
24417    fn next_row(&self) -> Self {
24418        Self(self.0 + 1)
24419    }
24420
24421    fn previous_row(&self) -> Self {
24422        Self(self.0.saturating_sub(1))
24423    }
24424
24425    fn minus(&self, other: Self) -> u32 {
24426        self.0 - other.0
24427    }
24428}
24429
24430impl RowExt for MultiBufferRow {
24431    fn as_f64(&self) -> f64 {
24432        self.0 as _
24433    }
24434
24435    fn next_row(&self) -> Self {
24436        Self(self.0 + 1)
24437    }
24438
24439    fn previous_row(&self) -> Self {
24440        Self(self.0.saturating_sub(1))
24441    }
24442
24443    fn minus(&self, other: Self) -> u32 {
24444        self.0 - other.0
24445    }
24446}
24447
24448trait RowRangeExt {
24449    type Row;
24450
24451    fn len(&self) -> usize;
24452
24453    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24454}
24455
24456impl RowRangeExt for Range<MultiBufferRow> {
24457    type Row = MultiBufferRow;
24458
24459    fn len(&self) -> usize {
24460        (self.end.0 - self.start.0) as usize
24461    }
24462
24463    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24464        (self.start.0..self.end.0).map(MultiBufferRow)
24465    }
24466}
24467
24468impl RowRangeExt for Range<DisplayRow> {
24469    type Row = DisplayRow;
24470
24471    fn len(&self) -> usize {
24472        (self.end.0 - self.start.0) as usize
24473    }
24474
24475    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24476        (self.start.0..self.end.0).map(DisplayRow)
24477    }
24478}
24479
24480/// If select range has more than one line, we
24481/// just point the cursor to range.start.
24482fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24483    if range.start.row == range.end.row {
24484        range
24485    } else {
24486        range.start..range.start
24487    }
24488}
24489pub struct KillRing(ClipboardItem);
24490impl Global for KillRing {}
24491
24492const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24493
24494enum BreakpointPromptEditAction {
24495    Log,
24496    Condition,
24497    HitCondition,
24498}
24499
24500struct BreakpointPromptEditor {
24501    pub(crate) prompt: Entity<Editor>,
24502    editor: WeakEntity<Editor>,
24503    breakpoint_anchor: Anchor,
24504    breakpoint: Breakpoint,
24505    edit_action: BreakpointPromptEditAction,
24506    block_ids: HashSet<CustomBlockId>,
24507    editor_margins: Arc<Mutex<EditorMargins>>,
24508    _subscriptions: Vec<Subscription>,
24509}
24510
24511impl BreakpointPromptEditor {
24512    const MAX_LINES: u8 = 4;
24513
24514    fn new(
24515        editor: WeakEntity<Editor>,
24516        breakpoint_anchor: Anchor,
24517        breakpoint: Breakpoint,
24518        edit_action: BreakpointPromptEditAction,
24519        window: &mut Window,
24520        cx: &mut Context<Self>,
24521    ) -> Self {
24522        let base_text = match edit_action {
24523            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24524            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24525            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24526        }
24527        .map(|msg| msg.to_string())
24528        .unwrap_or_default();
24529
24530        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24531        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24532
24533        let prompt = cx.new(|cx| {
24534            let mut prompt = Editor::new(
24535                EditorMode::AutoHeight {
24536                    min_lines: 1,
24537                    max_lines: Some(Self::MAX_LINES as usize),
24538                },
24539                buffer,
24540                None,
24541                window,
24542                cx,
24543            );
24544            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24545            prompt.set_show_cursor_when_unfocused(false, cx);
24546            prompt.set_placeholder_text(
24547                match edit_action {
24548                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24549                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24550                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24551                },
24552                window,
24553                cx,
24554            );
24555
24556            prompt
24557        });
24558
24559        Self {
24560            prompt,
24561            editor,
24562            breakpoint_anchor,
24563            breakpoint,
24564            edit_action,
24565            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24566            block_ids: Default::default(),
24567            _subscriptions: vec![],
24568        }
24569    }
24570
24571    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24572        self.block_ids.extend(block_ids)
24573    }
24574
24575    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24576        if let Some(editor) = self.editor.upgrade() {
24577            let message = self
24578                .prompt
24579                .read(cx)
24580                .buffer
24581                .read(cx)
24582                .as_singleton()
24583                .expect("A multi buffer in breakpoint prompt isn't possible")
24584                .read(cx)
24585                .as_rope()
24586                .to_string();
24587
24588            editor.update(cx, |editor, cx| {
24589                editor.edit_breakpoint_at_anchor(
24590                    self.breakpoint_anchor,
24591                    self.breakpoint.clone(),
24592                    match self.edit_action {
24593                        BreakpointPromptEditAction::Log => {
24594                            BreakpointEditAction::EditLogMessage(message.into())
24595                        }
24596                        BreakpointPromptEditAction::Condition => {
24597                            BreakpointEditAction::EditCondition(message.into())
24598                        }
24599                        BreakpointPromptEditAction::HitCondition => {
24600                            BreakpointEditAction::EditHitCondition(message.into())
24601                        }
24602                    },
24603                    cx,
24604                );
24605
24606                editor.remove_blocks(self.block_ids.clone(), None, cx);
24607                cx.focus_self(window);
24608            });
24609        }
24610    }
24611
24612    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24613        self.editor
24614            .update(cx, |editor, cx| {
24615                editor.remove_blocks(self.block_ids.clone(), None, cx);
24616                window.focus(&editor.focus_handle);
24617            })
24618            .log_err();
24619    }
24620
24621    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24622        let settings = ThemeSettings::get_global(cx);
24623        let text_style = TextStyle {
24624            color: if self.prompt.read(cx).read_only(cx) {
24625                cx.theme().colors().text_disabled
24626            } else {
24627                cx.theme().colors().text
24628            },
24629            font_family: settings.buffer_font.family.clone(),
24630            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24631            font_size: settings.buffer_font_size(cx).into(),
24632            font_weight: settings.buffer_font.weight,
24633            line_height: relative(settings.buffer_line_height.value()),
24634            ..Default::default()
24635        };
24636        EditorElement::new(
24637            &self.prompt,
24638            EditorStyle {
24639                background: cx.theme().colors().editor_background,
24640                local_player: cx.theme().players().local(),
24641                text: text_style,
24642                ..Default::default()
24643            },
24644        )
24645    }
24646}
24647
24648impl Render for BreakpointPromptEditor {
24649    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24650        let editor_margins = *self.editor_margins.lock();
24651        let gutter_dimensions = editor_margins.gutter;
24652        h_flex()
24653            .key_context("Editor")
24654            .bg(cx.theme().colors().editor_background)
24655            .border_y_1()
24656            .border_color(cx.theme().status().info_border)
24657            .size_full()
24658            .py(window.line_height() / 2.5)
24659            .on_action(cx.listener(Self::confirm))
24660            .on_action(cx.listener(Self::cancel))
24661            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24662            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24663    }
24664}
24665
24666impl Focusable for BreakpointPromptEditor {
24667    fn focus_handle(&self, cx: &App) -> FocusHandle {
24668        self.prompt.focus_handle(cx)
24669    }
24670}
24671
24672fn all_edits_insertions_or_deletions(
24673    edits: &Vec<(Range<Anchor>, String)>,
24674    snapshot: &MultiBufferSnapshot,
24675) -> bool {
24676    let mut all_insertions = true;
24677    let mut all_deletions = true;
24678
24679    for (range, new_text) in edits.iter() {
24680        let range_is_empty = range.to_offset(snapshot).is_empty();
24681        let text_is_empty = new_text.is_empty();
24682
24683        if range_is_empty != text_is_empty {
24684            if range_is_empty {
24685                all_deletions = false;
24686            } else {
24687                all_insertions = false;
24688            }
24689        } else {
24690            return false;
24691        }
24692
24693        if !all_insertions && !all_deletions {
24694            return false;
24695        }
24696    }
24697    all_insertions || all_deletions
24698}
24699
24700struct MissingEditPredictionKeybindingTooltip;
24701
24702impl Render for MissingEditPredictionKeybindingTooltip {
24703    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24704        ui::tooltip_container(cx, |container, cx| {
24705            container
24706                .flex_shrink_0()
24707                .max_w_80()
24708                .min_h(rems_from_px(124.))
24709                .justify_between()
24710                .child(
24711                    v_flex()
24712                        .flex_1()
24713                        .text_ui_sm(cx)
24714                        .child(Label::new("Conflict with Accept Keybinding"))
24715                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24716                )
24717                .child(
24718                    h_flex()
24719                        .pb_1()
24720                        .gap_1()
24721                        .items_end()
24722                        .w_full()
24723                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24724                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24725                        }))
24726                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24727                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24728                        })),
24729                )
24730        })
24731    }
24732}
24733
24734#[derive(Debug, Clone, Copy, PartialEq)]
24735pub struct LineHighlight {
24736    pub background: Background,
24737    pub border: Option<gpui::Hsla>,
24738    pub include_gutter: bool,
24739    pub type_id: Option<TypeId>,
24740}
24741
24742struct LineManipulationResult {
24743    pub new_text: String,
24744    pub line_count_before: usize,
24745    pub line_count_after: usize,
24746}
24747
24748fn render_diff_hunk_controls(
24749    row: u32,
24750    status: &DiffHunkStatus,
24751    hunk_range: Range<Anchor>,
24752    is_created_file: bool,
24753    line_height: Pixels,
24754    editor: &Entity<Editor>,
24755    _window: &mut Window,
24756    cx: &mut App,
24757) -> AnyElement {
24758    h_flex()
24759        .h(line_height)
24760        .mr_1()
24761        .gap_1()
24762        .px_0p5()
24763        .pb_1()
24764        .border_x_1()
24765        .border_b_1()
24766        .border_color(cx.theme().colors().border_variant)
24767        .rounded_b_lg()
24768        .bg(cx.theme().colors().editor_background)
24769        .gap_1()
24770        .block_mouse_except_scroll()
24771        .shadow_md()
24772        .child(if status.has_secondary_hunk() {
24773            Button::new(("stage", row as u64), "Stage")
24774                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24775                .tooltip({
24776                    let focus_handle = editor.focus_handle(cx);
24777                    move |_window, cx| {
24778                        Tooltip::for_action_in(
24779                            "Stage Hunk",
24780                            &::git::ToggleStaged,
24781                            &focus_handle,
24782                            cx,
24783                        )
24784                    }
24785                })
24786                .on_click({
24787                    let editor = editor.clone();
24788                    move |_event, _window, cx| {
24789                        editor.update(cx, |editor, cx| {
24790                            editor.stage_or_unstage_diff_hunks(
24791                                true,
24792                                vec![hunk_range.start..hunk_range.start],
24793                                cx,
24794                            );
24795                        });
24796                    }
24797                })
24798        } else {
24799            Button::new(("unstage", row as u64), "Unstage")
24800                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24801                .tooltip({
24802                    let focus_handle = editor.focus_handle(cx);
24803                    move |_window, cx| {
24804                        Tooltip::for_action_in(
24805                            "Unstage Hunk",
24806                            &::git::ToggleStaged,
24807                            &focus_handle,
24808                            cx,
24809                        )
24810                    }
24811                })
24812                .on_click({
24813                    let editor = editor.clone();
24814                    move |_event, _window, cx| {
24815                        editor.update(cx, |editor, cx| {
24816                            editor.stage_or_unstage_diff_hunks(
24817                                false,
24818                                vec![hunk_range.start..hunk_range.start],
24819                                cx,
24820                            );
24821                        });
24822                    }
24823                })
24824        })
24825        .child(
24826            Button::new(("restore", row as u64), "Restore")
24827                .tooltip({
24828                    let focus_handle = editor.focus_handle(cx);
24829                    move |_window, cx| {
24830                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24831                    }
24832                })
24833                .on_click({
24834                    let editor = editor.clone();
24835                    move |_event, window, cx| {
24836                        editor.update(cx, |editor, cx| {
24837                            let snapshot = editor.snapshot(window, cx);
24838                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24839                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24840                        });
24841                    }
24842                })
24843                .disabled(is_created_file),
24844        )
24845        .when(
24846            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24847            |el| {
24848                el.child(
24849                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24850                        .shape(IconButtonShape::Square)
24851                        .icon_size(IconSize::Small)
24852                        // .disabled(!has_multiple_hunks)
24853                        .tooltip({
24854                            let focus_handle = editor.focus_handle(cx);
24855                            move |_window, cx| {
24856                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24857                            }
24858                        })
24859                        .on_click({
24860                            let editor = editor.clone();
24861                            move |_event, window, cx| {
24862                                editor.update(cx, |editor, cx| {
24863                                    let snapshot = editor.snapshot(window, cx);
24864                                    let position =
24865                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24866                                    editor.go_to_hunk_before_or_after_position(
24867                                        &snapshot,
24868                                        position,
24869                                        Direction::Next,
24870                                        window,
24871                                        cx,
24872                                    );
24873                                    editor.expand_selected_diff_hunks(cx);
24874                                });
24875                            }
24876                        }),
24877                )
24878                .child(
24879                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24880                        .shape(IconButtonShape::Square)
24881                        .icon_size(IconSize::Small)
24882                        // .disabled(!has_multiple_hunks)
24883                        .tooltip({
24884                            let focus_handle = editor.focus_handle(cx);
24885                            move |_window, cx| {
24886                                Tooltip::for_action_in(
24887                                    "Previous Hunk",
24888                                    &GoToPreviousHunk,
24889                                    &focus_handle,
24890                                    cx,
24891                                )
24892                            }
24893                        })
24894                        .on_click({
24895                            let editor = editor.clone();
24896                            move |_event, window, cx| {
24897                                editor.update(cx, |editor, cx| {
24898                                    let snapshot = editor.snapshot(window, cx);
24899                                    let point =
24900                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24901                                    editor.go_to_hunk_before_or_after_position(
24902                                        &snapshot,
24903                                        point,
24904                                        Direction::Prev,
24905                                        window,
24906                                        cx,
24907                                    );
24908                                    editor.expand_selected_diff_hunks(cx);
24909                                });
24910                            }
24911                        }),
24912                )
24913            },
24914        )
24915        .into_any_element()
24916}
24917
24918pub fn multibuffer_context_lines(cx: &App) -> u32 {
24919    EditorSettings::try_get(cx)
24920        .map(|settings| settings.excerpt_context_lines)
24921        .unwrap_or(2)
24922        .min(32)
24923}