editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15mod blink_manager;
   16mod clangd_ext;
   17pub mod code_context_menus;
   18pub mod display_map;
   19mod editor_settings;
   20mod element;
   21mod git;
   22mod highlight_matching_bracket;
   23mod hover_links;
   24pub mod hover_popover;
   25mod indent_guides;
   26mod inlays;
   27pub mod items;
   28mod jsx_tag_auto_close;
   29mod linked_editing_ranges;
   30mod lsp_colors;
   31mod lsp_ext;
   32mod mouse_context_menu;
   33pub mod movement;
   34mod persistence;
   35mod rust_analyzer_ext;
   36pub mod scroll;
   37mod selections_collection;
   38pub mod tasks;
   39
   40#[cfg(test)]
   41mod code_completion_tests;
   42#[cfg(test)]
   43mod edit_prediction_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46mod signature_help;
   47#[cfg(any(test, feature = "test-support"))]
   48pub mod test;
   49
   50pub(crate) use actions::*;
   51pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   52pub use edit_prediction::Direction;
   53pub use editor_settings::{
   54    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   55    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   56};
   57pub use element::{
   58    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   59};
   60pub use git::blame::BlameRenderer;
   61pub use hover_popover::hover_markdown_style;
   62pub use inlays::Inlay;
   63pub use items::MAX_TAB_TITLE_LEN;
   64pub use lsp::CompletionContext;
   65pub use lsp_ext::lsp_tasks;
   66pub use multi_buffer::{
   67    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   68    RowInfo, ToOffset, ToPoint,
   69};
   70pub use text::Bias;
   71
   72use ::git::{
   73    Restore,
   74    blame::{BlameEntry, ParsedCommitMessage},
   75    status::FileStatus,
   76};
   77use aho_corasick::AhoCorasick;
   78use anyhow::{Context as _, Result, anyhow};
   79use blink_manager::BlinkManager;
   80use buffer_diff::DiffHunkStatus;
   81use client::{Collaborator, ParticipantIndex, parse_zed_link};
   82use clock::ReplicaId;
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   88use convert_case::{Case, Casing};
   89use dap::TelemetrySpawnLocation;
   90use display_map::*;
   91use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   92use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   93use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   94use futures::{
   95    FutureExt, StreamExt as _,
   96    future::{self, Shared, join},
   97    stream::FuturesUnordered,
   98};
   99use fuzzy::{StringMatch, StringMatchCandidate};
  100use git::blame::{GitBlame, GlobalBlameRenderer};
  101use gpui::{
  102    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  103    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  104    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  105    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  106    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  107    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  108    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  109    div, point, prelude::*, pulsating_between, px, relative, size,
  110};
  111use hover_links::{HoverLink, HoveredLinkState, find_file};
  112use hover_popover::{HoverState, hide_hover};
  113use indent_guides::ActiveIndentGuidesState;
  114use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  115use itertools::{Either, Itertools};
  116use language::{
  117    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  118    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  119    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  120    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  121    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  122    language_settings::{
  123        self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
  124        language_settings,
  125    },
  126    point_from_lsp, point_to_lsp, text_diff_with_options,
  127};
  128use linked_editing_ranges::refresh_linked_ranges;
  129use lsp::{
  130    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  131    LanguageServerId,
  132};
  133use lsp_colors::LspColorData;
  134use markdown::Markdown;
  135use mouse_context_menu::MouseContextMenu;
  136use movement::TextLayoutDetails;
  137use multi_buffer::{
  138    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  139};
  140use parking_lot::Mutex;
  141use persistence::DB;
  142use project::{
  143    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  144    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  145    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  146    ProjectPath, ProjectTransaction, TaskSourceKind,
  147    debugger::{
  148        breakpoint_store::{
  149            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  150            BreakpointStore, BreakpointStoreEvent,
  151        },
  152        session::{Session, SessionEvent},
  153    },
  154    git_store::GitStoreEvent,
  155    lsp_store::{
  156        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  157        OpenLspBufferHandle,
  158    },
  159    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  160};
  161use rand::seq::SliceRandom;
  162use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  163use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  164use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  165use serde::{Deserialize, Serialize};
  166use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  167use smallvec::{SmallVec, smallvec};
  168use snippet::Snippet;
  169use std::{
  170    any::{Any, TypeId},
  171    borrow::Cow,
  172    cell::{OnceCell, RefCell},
  173    cmp::{self, Ordering, Reverse},
  174    iter::{self, Peekable},
  175    mem,
  176    num::NonZeroU32,
  177    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  178    path::{Path, PathBuf},
  179    rc::Rc,
  180    sync::Arc,
  181    time::{Duration, Instant},
  182};
  183use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  184use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  185use theme::{
  186    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  187    observe_buffer_font_size_adjustment,
  188};
  189use ui::{
  190    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  191    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  192};
  193use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  194use workspace::{
  195    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  196    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  197    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  198    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  199    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  200    searchable::SearchEvent,
  201};
  202
  203use crate::{
  204    code_context_menus::CompletionsMenuSource,
  205    editor_settings::MultiCursorModifier,
  206    hover_links::{find_url, find_url_from_range},
  207    inlays::{
  208        InlineValueCache,
  209        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  210    },
  211    scroll::{ScrollOffset, ScrollPixelOffset},
  212    selections_collection::resolve_selections_wrapping_blocks,
  213    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  214};
  215
  216pub const FILE_HEADER_HEIGHT: u32 = 2;
  217pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  218const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  219const MAX_LINE_LEN: usize = 1024;
  220const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  221const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  222pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  223#[doc(hidden)]
  224pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  225pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  226
  227pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  230pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  231
  232pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  233pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  234pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  235
  236pub type RenderDiffHunkControlsFn = Arc<
  237    dyn Fn(
  238        u32,
  239        &DiffHunkStatus,
  240        Range<Anchor>,
  241        bool,
  242        Pixels,
  243        &Entity<Editor>,
  244        &mut Window,
  245        &mut App,
  246    ) -> AnyElement,
  247>;
  248
  249enum ReportEditorEvent {
  250    Saved { auto_saved: bool },
  251    EditorOpened,
  252    Closed,
  253}
  254
  255impl ReportEditorEvent {
  256    pub fn event_type(&self) -> &'static str {
  257        match self {
  258            Self::Saved { .. } => "Editor Saved",
  259            Self::EditorOpened => "Editor Opened",
  260            Self::Closed => "Editor Closed",
  261        }
  262    }
  263}
  264
  265pub enum ActiveDebugLine {}
  266pub enum DebugStackFrameLine {}
  267enum DocumentHighlightRead {}
  268enum DocumentHighlightWrite {}
  269enum InputComposition {}
  270pub enum PendingInput {}
  271enum SelectedTextHighlight {}
  272
  273pub enum ConflictsOuter {}
  274pub enum ConflictsOurs {}
  275pub enum ConflictsTheirs {}
  276pub enum ConflictsOursMarker {}
  277pub enum ConflictsTheirsMarker {}
  278
  279#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  280pub enum Navigated {
  281    Yes,
  282    No,
  283}
  284
  285impl Navigated {
  286    pub fn from_bool(yes: bool) -> Navigated {
  287        if yes { Navigated::Yes } else { Navigated::No }
  288    }
  289}
  290
  291#[derive(Debug, Clone, PartialEq, Eq)]
  292enum DisplayDiffHunk {
  293    Folded {
  294        display_row: DisplayRow,
  295    },
  296    Unfolded {
  297        is_created_file: bool,
  298        diff_base_byte_range: Range<usize>,
  299        display_row_range: Range<DisplayRow>,
  300        multi_buffer_range: Range<Anchor>,
  301        status: DiffHunkStatus,
  302    },
  303}
  304
  305pub enum HideMouseCursorOrigin {
  306    TypingAction,
  307    MovementAction,
  308}
  309
  310pub fn init_settings(cx: &mut App) {
  311    EditorSettings::register(cx);
  312}
  313
  314pub fn init(cx: &mut App) {
  315    init_settings(cx);
  316
  317    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  318
  319    workspace::register_project_item::<Editor>(cx);
  320    workspace::FollowableViewRegistry::register::<Editor>(cx);
  321    workspace::register_serializable_item::<Editor>(cx);
  322
  323    cx.observe_new(
  324        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  325            workspace.register_action(Editor::new_file);
  326            workspace.register_action(Editor::new_file_split);
  327            workspace.register_action(Editor::new_file_vertical);
  328            workspace.register_action(Editor::new_file_horizontal);
  329            workspace.register_action(Editor::cancel_language_server_work);
  330            workspace.register_action(Editor::toggle_focus);
  331        },
  332    )
  333    .detach();
  334
  335    cx.on_action(move |_: &workspace::NewFile, cx| {
  336        let app_state = workspace::AppState::global(cx);
  337        if let Some(app_state) = app_state.upgrade() {
  338            workspace::open_new(
  339                Default::default(),
  340                app_state,
  341                cx,
  342                |workspace, window, cx| {
  343                    Editor::new_file(workspace, &Default::default(), window, cx)
  344                },
  345            )
  346            .detach();
  347        }
  348    });
  349    cx.on_action(move |_: &workspace::NewWindow, cx| {
  350        let app_state = workspace::AppState::global(cx);
  351        if let Some(app_state) = app_state.upgrade() {
  352            workspace::open_new(
  353                Default::default(),
  354                app_state,
  355                cx,
  356                |workspace, window, cx| {
  357                    cx.activate(true);
  358                    Editor::new_file(workspace, &Default::default(), window, cx)
  359                },
  360            )
  361            .detach();
  362        }
  363    });
  364}
  365
  366pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  367    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  368}
  369
  370pub trait DiagnosticRenderer {
  371    fn render_group(
  372        &self,
  373        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  374        buffer_id: BufferId,
  375        snapshot: EditorSnapshot,
  376        editor: WeakEntity<Editor>,
  377        cx: &mut App,
  378    ) -> Vec<BlockProperties<Anchor>>;
  379
  380    fn render_hover(
  381        &self,
  382        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  383        range: Range<Point>,
  384        buffer_id: BufferId,
  385        cx: &mut App,
  386    ) -> Option<Entity<markdown::Markdown>>;
  387
  388    fn open_link(
  389        &self,
  390        editor: &mut Editor,
  391        link: SharedString,
  392        window: &mut Window,
  393        cx: &mut Context<Editor>,
  394    );
  395}
  396
  397pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  398
  399impl GlobalDiagnosticRenderer {
  400    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  401        cx.try_global::<Self>().map(|g| g.0.clone())
  402    }
  403}
  404
  405impl gpui::Global for GlobalDiagnosticRenderer {}
  406pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  407    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  408}
  409
  410pub struct SearchWithinRange;
  411
  412trait InvalidationRegion {
  413    fn ranges(&self) -> &[Range<Anchor>];
  414}
  415
  416#[derive(Clone, Debug, PartialEq)]
  417pub enum SelectPhase {
  418    Begin {
  419        position: DisplayPoint,
  420        add: bool,
  421        click_count: usize,
  422    },
  423    BeginColumnar {
  424        position: DisplayPoint,
  425        reset: bool,
  426        mode: ColumnarMode,
  427        goal_column: u32,
  428    },
  429    Extend {
  430        position: DisplayPoint,
  431        click_count: usize,
  432    },
  433    Update {
  434        position: DisplayPoint,
  435        goal_column: u32,
  436        scroll_delta: gpui::Point<f32>,
  437    },
  438    End,
  439}
  440
  441#[derive(Clone, Debug, PartialEq)]
  442pub enum ColumnarMode {
  443    FromMouse,
  444    FromSelection,
  445}
  446
  447#[derive(Clone, Debug)]
  448pub enum SelectMode {
  449    Character,
  450    Word(Range<Anchor>),
  451    Line(Range<Anchor>),
  452    All,
  453}
  454
  455#[derive(Clone, PartialEq, Eq, Debug)]
  456pub enum EditorMode {
  457    SingleLine,
  458    AutoHeight {
  459        min_lines: usize,
  460        max_lines: Option<usize>,
  461    },
  462    Full {
  463        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  464        scale_ui_elements_with_buffer_font_size: bool,
  465        /// When set to `true`, the editor will render a background for the active line.
  466        show_active_line_background: bool,
  467        /// When set to `true`, the editor's height will be determined by its content.
  468        sized_by_content: bool,
  469    },
  470    Minimap {
  471        parent: WeakEntity<Editor>,
  472    },
  473}
  474
  475impl EditorMode {
  476    pub fn full() -> Self {
  477        Self::Full {
  478            scale_ui_elements_with_buffer_font_size: true,
  479            show_active_line_background: true,
  480            sized_by_content: false,
  481        }
  482    }
  483
  484    #[inline]
  485    pub fn is_full(&self) -> bool {
  486        matches!(self, Self::Full { .. })
  487    }
  488
  489    #[inline]
  490    pub fn is_single_line(&self) -> bool {
  491        matches!(self, Self::SingleLine { .. })
  492    }
  493
  494    #[inline]
  495    fn is_minimap(&self) -> bool {
  496        matches!(self, Self::Minimap { .. })
  497    }
  498}
  499
  500#[derive(Copy, Clone, Debug)]
  501pub enum SoftWrap {
  502    /// Prefer not to wrap at all.
  503    ///
  504    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  505    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  506    GitDiff,
  507    /// Prefer a single line generally, unless an overly long line is encountered.
  508    None,
  509    /// Soft wrap lines that exceed the editor width.
  510    EditorWidth,
  511    /// Soft wrap lines at the preferred line length.
  512    Column(u32),
  513    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  514    Bounded(u32),
  515}
  516
  517#[derive(Clone)]
  518pub struct EditorStyle {
  519    pub background: Hsla,
  520    pub border: Hsla,
  521    pub local_player: PlayerColor,
  522    pub text: TextStyle,
  523    pub scrollbar_width: Pixels,
  524    pub syntax: Arc<SyntaxTheme>,
  525    pub status: StatusColors,
  526    pub inlay_hints_style: HighlightStyle,
  527    pub edit_prediction_styles: EditPredictionStyles,
  528    pub unnecessary_code_fade: f32,
  529    pub show_underlines: bool,
  530}
  531
  532impl Default for EditorStyle {
  533    fn default() -> Self {
  534        Self {
  535            background: Hsla::default(),
  536            border: Hsla::default(),
  537            local_player: PlayerColor::default(),
  538            text: TextStyle::default(),
  539            scrollbar_width: Pixels::default(),
  540            syntax: Default::default(),
  541            // HACK: Status colors don't have a real default.
  542            // We should look into removing the status colors from the editor
  543            // style and retrieve them directly from the theme.
  544            status: StatusColors::dark(),
  545            inlay_hints_style: HighlightStyle::default(),
  546            edit_prediction_styles: EditPredictionStyles {
  547                insertion: HighlightStyle::default(),
  548                whitespace: HighlightStyle::default(),
  549            },
  550            unnecessary_code_fade: Default::default(),
  551            show_underlines: true,
  552        }
  553    }
  554}
  555
  556pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  557    let show_background = language_settings::language_settings(None, None, cx)
  558        .inlay_hints
  559        .show_background;
  560
  561    let mut style = cx.theme().syntax().get("hint");
  562
  563    if style.color.is_none() {
  564        style.color = Some(cx.theme().status().hint);
  565    }
  566
  567    if !show_background {
  568        style.background_color = None;
  569        return style;
  570    }
  571
  572    if style.background_color.is_none() {
  573        style.background_color = Some(cx.theme().status().hint_background);
  574    }
  575
  576    style
  577}
  578
  579pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  580    EditPredictionStyles {
  581        insertion: HighlightStyle {
  582            color: Some(cx.theme().status().predictive),
  583            ..HighlightStyle::default()
  584        },
  585        whitespace: HighlightStyle {
  586            background_color: Some(cx.theme().status().created_background),
  587            ..HighlightStyle::default()
  588        },
  589    }
  590}
  591
  592type CompletionId = usize;
  593
  594pub(crate) enum EditDisplayMode {
  595    TabAccept,
  596    DiffPopover,
  597    Inline,
  598}
  599
  600enum EditPrediction {
  601    Edit {
  602        edits: Vec<(Range<Anchor>, String)>,
  603        edit_preview: Option<EditPreview>,
  604        display_mode: EditDisplayMode,
  605        snapshot: BufferSnapshot,
  606    },
  607    /// Move to a specific location in the active editor
  608    MoveWithin {
  609        target: Anchor,
  610        snapshot: BufferSnapshot,
  611    },
  612    /// Move to a specific location in a different editor (not the active one)
  613    MoveOutside {
  614        target: language::Anchor,
  615        snapshot: BufferSnapshot,
  616    },
  617}
  618
  619struct EditPredictionState {
  620    inlay_ids: Vec<InlayId>,
  621    completion: EditPrediction,
  622    completion_id: Option<SharedString>,
  623    invalidation_range: Option<Range<Anchor>>,
  624}
  625
  626enum EditPredictionSettings {
  627    Disabled,
  628    Enabled {
  629        show_in_menu: bool,
  630        preview_requires_modifier: bool,
  631    },
  632}
  633
  634enum EditPredictionHighlight {}
  635
  636#[derive(Debug, Clone)]
  637struct InlineDiagnostic {
  638    message: SharedString,
  639    group_id: usize,
  640    is_primary: bool,
  641    start: Point,
  642    severity: lsp::DiagnosticSeverity,
  643}
  644
  645pub enum MenuEditPredictionsPolicy {
  646    Never,
  647    ByProvider,
  648}
  649
  650pub enum EditPredictionPreview {
  651    /// Modifier is not pressed
  652    Inactive { released_too_fast: bool },
  653    /// Modifier pressed
  654    Active {
  655        since: Instant,
  656        previous_scroll_position: Option<ScrollAnchor>,
  657    },
  658}
  659
  660impl EditPredictionPreview {
  661    pub fn released_too_fast(&self) -> bool {
  662        match self {
  663            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  664            EditPredictionPreview::Active { .. } => false,
  665        }
  666    }
  667
  668    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  669        if let EditPredictionPreview::Active {
  670            previous_scroll_position,
  671            ..
  672        } = self
  673        {
  674            *previous_scroll_position = scroll_position;
  675        }
  676    }
  677}
  678
  679pub struct ContextMenuOptions {
  680    pub min_entries_visible: usize,
  681    pub max_entries_visible: usize,
  682    pub placement: Option<ContextMenuPlacement>,
  683}
  684
  685#[derive(Debug, Clone, PartialEq, Eq)]
  686pub enum ContextMenuPlacement {
  687    Above,
  688    Below,
  689}
  690
  691#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  692struct EditorActionId(usize);
  693
  694impl EditorActionId {
  695    pub fn post_inc(&mut self) -> Self {
  696        let answer = self.0;
  697
  698        *self = Self(answer + 1);
  699
  700        Self(answer)
  701    }
  702}
  703
  704// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  705// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  706
  707type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  708type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  709
  710#[derive(Default)]
  711struct ScrollbarMarkerState {
  712    scrollbar_size: Size<Pixels>,
  713    dirty: bool,
  714    markers: Arc<[PaintQuad]>,
  715    pending_refresh: Option<Task<Result<()>>>,
  716}
  717
  718impl ScrollbarMarkerState {
  719    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  720        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  721    }
  722}
  723
  724#[derive(Clone, Copy, PartialEq, Eq)]
  725pub enum MinimapVisibility {
  726    Disabled,
  727    Enabled {
  728        /// The configuration currently present in the users settings.
  729        setting_configuration: bool,
  730        /// Whether to override the currently set visibility from the users setting.
  731        toggle_override: bool,
  732    },
  733}
  734
  735impl MinimapVisibility {
  736    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  737        if mode.is_full() {
  738            Self::Enabled {
  739                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  740                toggle_override: false,
  741            }
  742        } else {
  743            Self::Disabled
  744        }
  745    }
  746
  747    fn hidden(&self) -> Self {
  748        match *self {
  749            Self::Enabled {
  750                setting_configuration,
  751                ..
  752            } => Self::Enabled {
  753                setting_configuration,
  754                toggle_override: setting_configuration,
  755            },
  756            Self::Disabled => Self::Disabled,
  757        }
  758    }
  759
  760    fn disabled(&self) -> bool {
  761        matches!(*self, Self::Disabled)
  762    }
  763
  764    fn settings_visibility(&self) -> bool {
  765        match *self {
  766            Self::Enabled {
  767                setting_configuration,
  768                ..
  769            } => setting_configuration,
  770            _ => false,
  771        }
  772    }
  773
  774    fn visible(&self) -> bool {
  775        match *self {
  776            Self::Enabled {
  777                setting_configuration,
  778                toggle_override,
  779            } => setting_configuration ^ toggle_override,
  780            _ => false,
  781        }
  782    }
  783
  784    fn toggle_visibility(&self) -> Self {
  785        match *self {
  786            Self::Enabled {
  787                toggle_override,
  788                setting_configuration,
  789            } => Self::Enabled {
  790                setting_configuration,
  791                toggle_override: !toggle_override,
  792            },
  793            Self::Disabled => Self::Disabled,
  794        }
  795    }
  796}
  797
  798#[derive(Clone, Debug)]
  799struct RunnableTasks {
  800    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  801    offset: multi_buffer::Anchor,
  802    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  803    column: u32,
  804    // Values of all named captures, including those starting with '_'
  805    extra_variables: HashMap<String, String>,
  806    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  807    context_range: Range<BufferOffset>,
  808}
  809
  810impl RunnableTasks {
  811    fn resolve<'a>(
  812        &'a self,
  813        cx: &'a task::TaskContext,
  814    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  815        self.templates.iter().filter_map(|(kind, template)| {
  816            template
  817                .resolve_task(&kind.to_id_base(), cx)
  818                .map(|task| (kind.clone(), task))
  819        })
  820    }
  821}
  822
  823#[derive(Clone)]
  824pub struct ResolvedTasks {
  825    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  826    position: Anchor,
  827}
  828
  829#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  830struct BufferOffset(usize);
  831
  832/// Addons allow storing per-editor state in other crates (e.g. Vim)
  833pub trait Addon: 'static {
  834    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  835
  836    fn render_buffer_header_controls(
  837        &self,
  838        _: &ExcerptInfo,
  839        _: &Window,
  840        _: &App,
  841    ) -> Option<AnyElement> {
  842        None
  843    }
  844
  845    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  846        None
  847    }
  848
  849    fn to_any(&self) -> &dyn std::any::Any;
  850
  851    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  852        None
  853    }
  854}
  855
  856struct ChangeLocation {
  857    current: Option<Vec<Anchor>>,
  858    original: Vec<Anchor>,
  859}
  860impl ChangeLocation {
  861    fn locations(&self) -> &[Anchor] {
  862        self.current.as_ref().unwrap_or(&self.original)
  863    }
  864}
  865
  866/// A set of caret positions, registered when the editor was edited.
  867pub struct ChangeList {
  868    changes: Vec<ChangeLocation>,
  869    /// Currently "selected" change.
  870    position: Option<usize>,
  871}
  872
  873impl ChangeList {
  874    pub fn new() -> Self {
  875        Self {
  876            changes: Vec::new(),
  877            position: None,
  878        }
  879    }
  880
  881    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  882    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  883    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  884        if self.changes.is_empty() {
  885            return None;
  886        }
  887
  888        let prev = self.position.unwrap_or(self.changes.len());
  889        let next = if direction == Direction::Prev {
  890            prev.saturating_sub(count)
  891        } else {
  892            (prev + count).min(self.changes.len() - 1)
  893        };
  894        self.position = Some(next);
  895        self.changes.get(next).map(|change| change.locations())
  896    }
  897
  898    /// Adds a new change to the list, resetting the change list position.
  899    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  900        self.position.take();
  901        if let Some(last) = self.changes.last_mut()
  902            && group
  903        {
  904            last.current = Some(new_positions)
  905        } else {
  906            self.changes.push(ChangeLocation {
  907                original: new_positions,
  908                current: None,
  909            });
  910        }
  911    }
  912
  913    pub fn last(&self) -> Option<&[Anchor]> {
  914        self.changes.last().map(|change| change.locations())
  915    }
  916
  917    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  918        self.changes.last().map(|change| change.original.as_slice())
  919    }
  920
  921    pub fn invert_last_group(&mut self) {
  922        if let Some(last) = self.changes.last_mut()
  923            && let Some(current) = last.current.as_mut()
  924        {
  925            mem::swap(&mut last.original, current);
  926        }
  927    }
  928}
  929
  930#[derive(Clone)]
  931struct InlineBlamePopoverState {
  932    scroll_handle: ScrollHandle,
  933    commit_message: Option<ParsedCommitMessage>,
  934    markdown: Entity<Markdown>,
  935}
  936
  937struct InlineBlamePopover {
  938    position: gpui::Point<Pixels>,
  939    hide_task: Option<Task<()>>,
  940    popover_bounds: Option<Bounds<Pixels>>,
  941    popover_state: InlineBlamePopoverState,
  942    keyboard_grace: bool,
  943}
  944
  945enum SelectionDragState {
  946    /// State when no drag related activity is detected.
  947    None,
  948    /// State when the mouse is down on a selection that is about to be dragged.
  949    ReadyToDrag {
  950        selection: Selection<Anchor>,
  951        click_position: gpui::Point<Pixels>,
  952        mouse_down_time: Instant,
  953    },
  954    /// State when the mouse is dragging the selection in the editor.
  955    Dragging {
  956        selection: Selection<Anchor>,
  957        drop_cursor: Selection<Anchor>,
  958        hide_drop_cursor: bool,
  959    },
  960}
  961
  962enum ColumnarSelectionState {
  963    FromMouse {
  964        selection_tail: Anchor,
  965        display_point: Option<DisplayPoint>,
  966    },
  967    FromSelection {
  968        selection_tail: Anchor,
  969    },
  970}
  971
  972/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  973/// a breakpoint on them.
  974#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  975struct PhantomBreakpointIndicator {
  976    display_row: DisplayRow,
  977    /// There's a small debounce between hovering over the line and showing the indicator.
  978    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  979    is_active: bool,
  980    collides_with_existing_breakpoint: bool,
  981}
  982
  983/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  984///
  985/// See the [module level documentation](self) for more information.
  986pub struct Editor {
  987    focus_handle: FocusHandle,
  988    last_focused_descendant: Option<WeakFocusHandle>,
  989    /// The text buffer being edited
  990    buffer: Entity<MultiBuffer>,
  991    /// Map of how text in the buffer should be displayed.
  992    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  993    pub display_map: Entity<DisplayMap>,
  994    placeholder_display_map: Option<Entity<DisplayMap>>,
  995    pub selections: SelectionsCollection,
  996    pub scroll_manager: ScrollManager,
  997    /// When inline assist editors are linked, they all render cursors because
  998    /// typing enters text into each of them, even the ones that aren't focused.
  999    pub(crate) show_cursor_when_unfocused: bool,
 1000    columnar_selection_state: Option<ColumnarSelectionState>,
 1001    add_selections_state: Option<AddSelectionsState>,
 1002    select_next_state: Option<SelectNextState>,
 1003    select_prev_state: Option<SelectNextState>,
 1004    selection_history: SelectionHistory,
 1005    defer_selection_effects: bool,
 1006    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1007    autoclose_regions: Vec<AutocloseRegion>,
 1008    snippet_stack: InvalidationStack<SnippetState>,
 1009    select_syntax_node_history: SelectSyntaxNodeHistory,
 1010    ime_transaction: Option<TransactionId>,
 1011    pub diagnostics_max_severity: DiagnosticSeverity,
 1012    active_diagnostics: ActiveDiagnostic,
 1013    show_inline_diagnostics: bool,
 1014    inline_diagnostics_update: Task<()>,
 1015    inline_diagnostics_enabled: bool,
 1016    diagnostics_enabled: bool,
 1017    word_completions_enabled: bool,
 1018    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1019    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1020    hard_wrap: Option<usize>,
 1021    project: Option<Entity<Project>>,
 1022    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1023    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1024    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1025    blink_manager: Entity<BlinkManager>,
 1026    show_cursor_names: bool,
 1027    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1028    pub show_local_selections: bool,
 1029    mode: EditorMode,
 1030    show_breadcrumbs: bool,
 1031    show_gutter: bool,
 1032    show_scrollbars: ScrollbarAxes,
 1033    minimap_visibility: MinimapVisibility,
 1034    offset_content: bool,
 1035    disable_expand_excerpt_buttons: bool,
 1036    show_line_numbers: Option<bool>,
 1037    use_relative_line_numbers: Option<bool>,
 1038    show_git_diff_gutter: Option<bool>,
 1039    show_code_actions: Option<bool>,
 1040    show_runnables: Option<bool>,
 1041    show_breakpoints: Option<bool>,
 1042    show_wrap_guides: Option<bool>,
 1043    show_indent_guides: Option<bool>,
 1044    highlight_order: usize,
 1045    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1046    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1047    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1048    scrollbar_marker_state: ScrollbarMarkerState,
 1049    active_indent_guides_state: ActiveIndentGuidesState,
 1050    nav_history: Option<ItemNavHistory>,
 1051    context_menu: RefCell<Option<CodeContextMenu>>,
 1052    context_menu_options: Option<ContextMenuOptions>,
 1053    mouse_context_menu: Option<MouseContextMenu>,
 1054    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1055    inline_blame_popover: Option<InlineBlamePopover>,
 1056    inline_blame_popover_show_task: Option<Task<()>>,
 1057    signature_help_state: SignatureHelpState,
 1058    auto_signature_help: Option<bool>,
 1059    find_all_references_task_sources: Vec<Anchor>,
 1060    next_completion_id: CompletionId,
 1061    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1062    code_actions_task: Option<Task<Result<()>>>,
 1063    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1064    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1065    document_highlights_task: Option<Task<()>>,
 1066    linked_editing_range_task: Option<Task<Option<()>>>,
 1067    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1068    pending_rename: Option<RenameState>,
 1069    searchable: bool,
 1070    cursor_shape: CursorShape,
 1071    current_line_highlight: Option<CurrentLineHighlight>,
 1072    collapse_matches: bool,
 1073    autoindent_mode: Option<AutoindentMode>,
 1074    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1075    input_enabled: bool,
 1076    use_modal_editing: bool,
 1077    read_only: bool,
 1078    leader_id: Option<CollaboratorId>,
 1079    remote_id: Option<ViewId>,
 1080    pub hover_state: HoverState,
 1081    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1082    gutter_hovered: bool,
 1083    hovered_link_state: Option<HoveredLinkState>,
 1084    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1085    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1086    active_edit_prediction: Option<EditPredictionState>,
 1087    /// Used to prevent flickering as the user types while the menu is open
 1088    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1089    edit_prediction_settings: EditPredictionSettings,
 1090    edit_predictions_hidden_for_vim_mode: bool,
 1091    show_edit_predictions_override: Option<bool>,
 1092    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1093    edit_prediction_preview: EditPredictionPreview,
 1094    edit_prediction_indent_conflict: bool,
 1095    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1096    next_inlay_id: usize,
 1097    next_color_inlay_id: usize,
 1098    _subscriptions: Vec<Subscription>,
 1099    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1100    gutter_dimensions: GutterDimensions,
 1101    style: Option<EditorStyle>,
 1102    text_style_refinement: Option<TextStyleRefinement>,
 1103    next_editor_action_id: EditorActionId,
 1104    editor_actions: Rc<
 1105        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1106    >,
 1107    use_autoclose: bool,
 1108    use_auto_surround: bool,
 1109    auto_replace_emoji_shortcode: bool,
 1110    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1111    show_git_blame_gutter: bool,
 1112    show_git_blame_inline: bool,
 1113    show_git_blame_inline_delay_task: Option<Task<()>>,
 1114    git_blame_inline_enabled: bool,
 1115    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1116    serialize_dirty_buffers: bool,
 1117    show_selection_menu: Option<bool>,
 1118    blame: Option<Entity<GitBlame>>,
 1119    blame_subscription: Option<Subscription>,
 1120    custom_context_menu: Option<
 1121        Box<
 1122            dyn 'static
 1123                + Fn(
 1124                    &mut Self,
 1125                    DisplayPoint,
 1126                    &mut Window,
 1127                    &mut Context<Self>,
 1128                ) -> Option<Entity<ui::ContextMenu>>,
 1129        >,
 1130    >,
 1131    last_bounds: Option<Bounds<Pixels>>,
 1132    last_position_map: Option<Rc<PositionMap>>,
 1133    expect_bounds_change: Option<Bounds<Pixels>>,
 1134    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1135    tasks_update_task: Option<Task<()>>,
 1136    breakpoint_store: Option<Entity<BreakpointStore>>,
 1137    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1138    hovered_diff_hunk_row: Option<DisplayRow>,
 1139    pull_diagnostics_task: Task<()>,
 1140    in_project_search: bool,
 1141    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1142    breadcrumb_header: Option<String>,
 1143    focused_block: Option<FocusedBlock>,
 1144    next_scroll_position: NextScrollCursorCenterTopBottom,
 1145    addons: HashMap<TypeId, Box<dyn Addon>>,
 1146    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1147    load_diff_task: Option<Shared<Task<()>>>,
 1148    /// Whether we are temporarily displaying a diff other than git's
 1149    temporary_diff_override: bool,
 1150    selection_mark_mode: bool,
 1151    toggle_fold_multiple_buffers: Task<()>,
 1152    _scroll_cursor_center_top_bottom_task: Task<()>,
 1153    serialize_selections: Task<()>,
 1154    serialize_folds: Task<()>,
 1155    mouse_cursor_hidden: bool,
 1156    minimap: Option<Entity<Self>>,
 1157    hide_mouse_mode: HideMouseMode,
 1158    pub change_list: ChangeList,
 1159    inline_value_cache: InlineValueCache,
 1160    selection_drag_state: SelectionDragState,
 1161    colors: Option<LspColorData>,
 1162    post_scroll_update: Task<()>,
 1163    refresh_colors_task: Task<()>,
 1164    inlay_hints: Option<LspInlayHintData>,
 1165    folding_newlines: Task<()>,
 1166    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1167}
 1168
 1169fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1170    if debounce_ms > 0 {
 1171        Some(Duration::from_millis(debounce_ms))
 1172    } else {
 1173        None
 1174    }
 1175}
 1176
 1177#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1178enum NextScrollCursorCenterTopBottom {
 1179    #[default]
 1180    Center,
 1181    Top,
 1182    Bottom,
 1183}
 1184
 1185impl NextScrollCursorCenterTopBottom {
 1186    fn next(&self) -> Self {
 1187        match self {
 1188            Self::Center => Self::Top,
 1189            Self::Top => Self::Bottom,
 1190            Self::Bottom => Self::Center,
 1191        }
 1192    }
 1193}
 1194
 1195#[derive(Clone)]
 1196pub struct EditorSnapshot {
 1197    pub mode: EditorMode,
 1198    show_gutter: bool,
 1199    show_line_numbers: Option<bool>,
 1200    show_git_diff_gutter: Option<bool>,
 1201    show_code_actions: Option<bool>,
 1202    show_runnables: Option<bool>,
 1203    show_breakpoints: Option<bool>,
 1204    git_blame_gutter_max_author_length: Option<usize>,
 1205    pub display_snapshot: DisplaySnapshot,
 1206    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1207    is_focused: bool,
 1208    scroll_anchor: ScrollAnchor,
 1209    ongoing_scroll: OngoingScroll,
 1210    current_line_highlight: CurrentLineHighlight,
 1211    gutter_hovered: bool,
 1212}
 1213
 1214#[derive(Default, Debug, Clone, Copy)]
 1215pub struct GutterDimensions {
 1216    pub left_padding: Pixels,
 1217    pub right_padding: Pixels,
 1218    pub width: Pixels,
 1219    pub margin: Pixels,
 1220    pub git_blame_entries_width: Option<Pixels>,
 1221}
 1222
 1223impl GutterDimensions {
 1224    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1225        Self {
 1226            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1227            ..Default::default()
 1228        }
 1229    }
 1230
 1231    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1232        -cx.text_system().descent(font_id, font_size)
 1233    }
 1234    /// The full width of the space taken up by the gutter.
 1235    pub fn full_width(&self) -> Pixels {
 1236        self.margin + self.width
 1237    }
 1238
 1239    /// The width of the space reserved for the fold indicators,
 1240    /// use alongside 'justify_end' and `gutter_width` to
 1241    /// right align content with the line numbers
 1242    pub fn fold_area_width(&self) -> Pixels {
 1243        self.margin + self.right_padding
 1244    }
 1245}
 1246
 1247struct CharacterDimensions {
 1248    em_width: Pixels,
 1249    em_advance: Pixels,
 1250    line_height: Pixels,
 1251}
 1252
 1253#[derive(Debug)]
 1254pub struct RemoteSelection {
 1255    pub replica_id: ReplicaId,
 1256    pub selection: Selection<Anchor>,
 1257    pub cursor_shape: CursorShape,
 1258    pub collaborator_id: CollaboratorId,
 1259    pub line_mode: bool,
 1260    pub user_name: Option<SharedString>,
 1261    pub color: PlayerColor,
 1262}
 1263
 1264#[derive(Clone, Debug)]
 1265struct SelectionHistoryEntry {
 1266    selections: Arc<[Selection<Anchor>]>,
 1267    select_next_state: Option<SelectNextState>,
 1268    select_prev_state: Option<SelectNextState>,
 1269    add_selections_state: Option<AddSelectionsState>,
 1270}
 1271
 1272#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1273enum SelectionHistoryMode {
 1274    Normal,
 1275    Undoing,
 1276    Redoing,
 1277    Skipping,
 1278}
 1279
 1280#[derive(Clone, PartialEq, Eq, Hash)]
 1281struct HoveredCursor {
 1282    replica_id: ReplicaId,
 1283    selection_id: usize,
 1284}
 1285
 1286impl Default for SelectionHistoryMode {
 1287    fn default() -> Self {
 1288        Self::Normal
 1289    }
 1290}
 1291
 1292#[derive(Debug)]
 1293/// SelectionEffects controls the side-effects of updating the selection.
 1294///
 1295/// The default behaviour does "what you mostly want":
 1296/// - it pushes to the nav history if the cursor moved by >10 lines
 1297/// - it re-triggers completion requests
 1298/// - it scrolls to fit
 1299///
 1300/// You might want to modify these behaviours. For example when doing a "jump"
 1301/// like go to definition, we always want to add to nav history; but when scrolling
 1302/// in vim mode we never do.
 1303///
 1304/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1305/// move.
 1306#[derive(Clone)]
 1307pub struct SelectionEffects {
 1308    nav_history: Option<bool>,
 1309    completions: bool,
 1310    scroll: Option<Autoscroll>,
 1311}
 1312
 1313impl Default for SelectionEffects {
 1314    fn default() -> Self {
 1315        Self {
 1316            nav_history: None,
 1317            completions: true,
 1318            scroll: Some(Autoscroll::fit()),
 1319        }
 1320    }
 1321}
 1322impl SelectionEffects {
 1323    pub fn scroll(scroll: Autoscroll) -> Self {
 1324        Self {
 1325            scroll: Some(scroll),
 1326            ..Default::default()
 1327        }
 1328    }
 1329
 1330    pub fn no_scroll() -> Self {
 1331        Self {
 1332            scroll: None,
 1333            ..Default::default()
 1334        }
 1335    }
 1336
 1337    pub fn completions(self, completions: bool) -> Self {
 1338        Self {
 1339            completions,
 1340            ..self
 1341        }
 1342    }
 1343
 1344    pub fn nav_history(self, nav_history: bool) -> Self {
 1345        Self {
 1346            nav_history: Some(nav_history),
 1347            ..self
 1348        }
 1349    }
 1350}
 1351
 1352struct DeferredSelectionEffectsState {
 1353    changed: bool,
 1354    effects: SelectionEffects,
 1355    old_cursor_position: Anchor,
 1356    history_entry: SelectionHistoryEntry,
 1357}
 1358
 1359#[derive(Default)]
 1360struct SelectionHistory {
 1361    #[allow(clippy::type_complexity)]
 1362    selections_by_transaction:
 1363        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1364    mode: SelectionHistoryMode,
 1365    undo_stack: VecDeque<SelectionHistoryEntry>,
 1366    redo_stack: VecDeque<SelectionHistoryEntry>,
 1367}
 1368
 1369impl SelectionHistory {
 1370    #[track_caller]
 1371    fn insert_transaction(
 1372        &mut self,
 1373        transaction_id: TransactionId,
 1374        selections: Arc<[Selection<Anchor>]>,
 1375    ) {
 1376        if selections.is_empty() {
 1377            log::error!(
 1378                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1379                std::panic::Location::caller()
 1380            );
 1381            return;
 1382        }
 1383        self.selections_by_transaction
 1384            .insert(transaction_id, (selections, None));
 1385    }
 1386
 1387    #[allow(clippy::type_complexity)]
 1388    fn transaction(
 1389        &self,
 1390        transaction_id: TransactionId,
 1391    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1392        self.selections_by_transaction.get(&transaction_id)
 1393    }
 1394
 1395    #[allow(clippy::type_complexity)]
 1396    fn transaction_mut(
 1397        &mut self,
 1398        transaction_id: TransactionId,
 1399    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1400        self.selections_by_transaction.get_mut(&transaction_id)
 1401    }
 1402
 1403    fn push(&mut self, entry: SelectionHistoryEntry) {
 1404        if !entry.selections.is_empty() {
 1405            match self.mode {
 1406                SelectionHistoryMode::Normal => {
 1407                    self.push_undo(entry);
 1408                    self.redo_stack.clear();
 1409                }
 1410                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1411                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1412                SelectionHistoryMode::Skipping => {}
 1413            }
 1414        }
 1415    }
 1416
 1417    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1418        if self
 1419            .undo_stack
 1420            .back()
 1421            .is_none_or(|e| e.selections != entry.selections)
 1422        {
 1423            self.undo_stack.push_back(entry);
 1424            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1425                self.undo_stack.pop_front();
 1426            }
 1427        }
 1428    }
 1429
 1430    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1431        if self
 1432            .redo_stack
 1433            .back()
 1434            .is_none_or(|e| e.selections != entry.selections)
 1435        {
 1436            self.redo_stack.push_back(entry);
 1437            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1438                self.redo_stack.pop_front();
 1439            }
 1440        }
 1441    }
 1442}
 1443
 1444#[derive(Clone, Copy)]
 1445pub struct RowHighlightOptions {
 1446    pub autoscroll: bool,
 1447    pub include_gutter: bool,
 1448}
 1449
 1450impl Default for RowHighlightOptions {
 1451    fn default() -> Self {
 1452        Self {
 1453            autoscroll: Default::default(),
 1454            include_gutter: true,
 1455        }
 1456    }
 1457}
 1458
 1459struct RowHighlight {
 1460    index: usize,
 1461    range: Range<Anchor>,
 1462    color: Hsla,
 1463    options: RowHighlightOptions,
 1464    type_id: TypeId,
 1465}
 1466
 1467#[derive(Clone, Debug)]
 1468struct AddSelectionsState {
 1469    groups: Vec<AddSelectionsGroup>,
 1470}
 1471
 1472#[derive(Clone, Debug)]
 1473struct AddSelectionsGroup {
 1474    above: bool,
 1475    stack: Vec<usize>,
 1476}
 1477
 1478#[derive(Clone)]
 1479struct SelectNextState {
 1480    query: AhoCorasick,
 1481    wordwise: bool,
 1482    done: bool,
 1483}
 1484
 1485impl std::fmt::Debug for SelectNextState {
 1486    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1487        f.debug_struct(std::any::type_name::<Self>())
 1488            .field("wordwise", &self.wordwise)
 1489            .field("done", &self.done)
 1490            .finish()
 1491    }
 1492}
 1493
 1494#[derive(Debug)]
 1495struct AutocloseRegion {
 1496    selection_id: usize,
 1497    range: Range<Anchor>,
 1498    pair: BracketPair,
 1499}
 1500
 1501#[derive(Debug)]
 1502struct SnippetState {
 1503    ranges: Vec<Vec<Range<Anchor>>>,
 1504    active_index: usize,
 1505    choices: Vec<Option<Vec<String>>>,
 1506}
 1507
 1508#[doc(hidden)]
 1509pub struct RenameState {
 1510    pub range: Range<Anchor>,
 1511    pub old_name: Arc<str>,
 1512    pub editor: Entity<Editor>,
 1513    block_id: CustomBlockId,
 1514}
 1515
 1516struct InvalidationStack<T>(Vec<T>);
 1517
 1518struct RegisteredEditPredictionProvider {
 1519    provider: Arc<dyn EditPredictionProviderHandle>,
 1520    _subscription: Subscription,
 1521}
 1522
 1523#[derive(Debug, PartialEq, Eq)]
 1524pub struct ActiveDiagnosticGroup {
 1525    pub active_range: Range<Anchor>,
 1526    pub active_message: String,
 1527    pub group_id: usize,
 1528    pub blocks: HashSet<CustomBlockId>,
 1529}
 1530
 1531#[derive(Debug, PartialEq, Eq)]
 1532
 1533pub(crate) enum ActiveDiagnostic {
 1534    None,
 1535    All,
 1536    Group(ActiveDiagnosticGroup),
 1537}
 1538
 1539#[derive(Serialize, Deserialize, Clone, Debug)]
 1540pub struct ClipboardSelection {
 1541    /// The number of bytes in this selection.
 1542    pub len: usize,
 1543    /// Whether this was a full-line selection.
 1544    pub is_entire_line: bool,
 1545    /// The indentation of the first line when this content was originally copied.
 1546    pub first_line_indent: u32,
 1547}
 1548
 1549// selections, scroll behavior, was newest selection reversed
 1550type SelectSyntaxNodeHistoryState = (
 1551    Box<[Selection<usize>]>,
 1552    SelectSyntaxNodeScrollBehavior,
 1553    bool,
 1554);
 1555
 1556#[derive(Default)]
 1557struct SelectSyntaxNodeHistory {
 1558    stack: Vec<SelectSyntaxNodeHistoryState>,
 1559    // disable temporarily to allow changing selections without losing the stack
 1560    pub disable_clearing: bool,
 1561}
 1562
 1563impl SelectSyntaxNodeHistory {
 1564    pub fn try_clear(&mut self) {
 1565        if !self.disable_clearing {
 1566            self.stack.clear();
 1567        }
 1568    }
 1569
 1570    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1571        self.stack.push(selection);
 1572    }
 1573
 1574    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1575        self.stack.pop()
 1576    }
 1577}
 1578
 1579enum SelectSyntaxNodeScrollBehavior {
 1580    CursorTop,
 1581    FitSelection,
 1582    CursorBottom,
 1583}
 1584
 1585#[derive(Debug)]
 1586pub(crate) struct NavigationData {
 1587    cursor_anchor: Anchor,
 1588    cursor_position: Point,
 1589    scroll_anchor: ScrollAnchor,
 1590    scroll_top_row: u32,
 1591}
 1592
 1593#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1594pub enum GotoDefinitionKind {
 1595    Symbol,
 1596    Declaration,
 1597    Type,
 1598    Implementation,
 1599}
 1600
 1601pub enum FormatTarget {
 1602    Buffers(HashSet<Entity<Buffer>>),
 1603    Ranges(Vec<Range<MultiBufferPoint>>),
 1604}
 1605
 1606pub(crate) struct FocusedBlock {
 1607    id: BlockId,
 1608    focus_handle: WeakFocusHandle,
 1609}
 1610
 1611#[derive(Clone)]
 1612enum JumpData {
 1613    MultiBufferRow {
 1614        row: MultiBufferRow,
 1615        line_offset_from_top: u32,
 1616    },
 1617    MultiBufferPoint {
 1618        excerpt_id: ExcerptId,
 1619        position: Point,
 1620        anchor: text::Anchor,
 1621        line_offset_from_top: u32,
 1622    },
 1623}
 1624
 1625pub enum MultibufferSelectionMode {
 1626    First,
 1627    All,
 1628}
 1629
 1630#[derive(Clone, Copy, Debug, Default)]
 1631pub struct RewrapOptions {
 1632    pub override_language_settings: bool,
 1633    pub preserve_existing_whitespace: bool,
 1634}
 1635
 1636impl Editor {
 1637    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1638        let buffer = cx.new(|cx| Buffer::local("", cx));
 1639        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1640        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1641    }
 1642
 1643    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1644        let buffer = cx.new(|cx| Buffer::local("", cx));
 1645        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1646        Self::new(EditorMode::full(), buffer, None, window, cx)
 1647    }
 1648
 1649    pub fn auto_height(
 1650        min_lines: usize,
 1651        max_lines: usize,
 1652        window: &mut Window,
 1653        cx: &mut Context<Self>,
 1654    ) -> Self {
 1655        let buffer = cx.new(|cx| Buffer::local("", cx));
 1656        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1657        Self::new(
 1658            EditorMode::AutoHeight {
 1659                min_lines,
 1660                max_lines: Some(max_lines),
 1661            },
 1662            buffer,
 1663            None,
 1664            window,
 1665            cx,
 1666        )
 1667    }
 1668
 1669    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1670    /// The editor grows as tall as needed to fit its content.
 1671    pub fn auto_height_unbounded(
 1672        min_lines: usize,
 1673        window: &mut Window,
 1674        cx: &mut Context<Self>,
 1675    ) -> Self {
 1676        let buffer = cx.new(|cx| Buffer::local("", cx));
 1677        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1678        Self::new(
 1679            EditorMode::AutoHeight {
 1680                min_lines,
 1681                max_lines: None,
 1682            },
 1683            buffer,
 1684            None,
 1685            window,
 1686            cx,
 1687        )
 1688    }
 1689
 1690    pub fn for_buffer(
 1691        buffer: Entity<Buffer>,
 1692        project: Option<Entity<Project>>,
 1693        window: &mut Window,
 1694        cx: &mut Context<Self>,
 1695    ) -> Self {
 1696        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1697        Self::new(EditorMode::full(), buffer, project, window, cx)
 1698    }
 1699
 1700    pub fn for_multibuffer(
 1701        buffer: Entity<MultiBuffer>,
 1702        project: Option<Entity<Project>>,
 1703        window: &mut Window,
 1704        cx: &mut Context<Self>,
 1705    ) -> Self {
 1706        Self::new(EditorMode::full(), buffer, project, window, cx)
 1707    }
 1708
 1709    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1710        let mut clone = Self::new(
 1711            self.mode.clone(),
 1712            self.buffer.clone(),
 1713            self.project.clone(),
 1714            window,
 1715            cx,
 1716        );
 1717        self.display_map.update(cx, |display_map, cx| {
 1718            let snapshot = display_map.snapshot(cx);
 1719            clone.display_map.update(cx, |display_map, cx| {
 1720                display_map.set_state(&snapshot, cx);
 1721            });
 1722        });
 1723        clone.folds_did_change(cx);
 1724        clone.selections.clone_state(&self.selections);
 1725        clone.scroll_manager.clone_state(&self.scroll_manager);
 1726        clone.searchable = self.searchable;
 1727        clone.read_only = self.read_only;
 1728        clone
 1729    }
 1730
 1731    pub fn new(
 1732        mode: EditorMode,
 1733        buffer: Entity<MultiBuffer>,
 1734        project: Option<Entity<Project>>,
 1735        window: &mut Window,
 1736        cx: &mut Context<Self>,
 1737    ) -> Self {
 1738        Editor::new_internal(mode, buffer, project, None, window, cx)
 1739    }
 1740
 1741    fn new_internal(
 1742        mode: EditorMode,
 1743        multi_buffer: Entity<MultiBuffer>,
 1744        project: Option<Entity<Project>>,
 1745        display_map: Option<Entity<DisplayMap>>,
 1746        window: &mut Window,
 1747        cx: &mut Context<Self>,
 1748    ) -> Self {
 1749        debug_assert!(
 1750            display_map.is_none() || mode.is_minimap(),
 1751            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1752        );
 1753
 1754        let full_mode = mode.is_full();
 1755        let is_minimap = mode.is_minimap();
 1756        let diagnostics_max_severity = if full_mode {
 1757            EditorSettings::get_global(cx)
 1758                .diagnostics_max_severity
 1759                .unwrap_or(DiagnosticSeverity::Hint)
 1760        } else {
 1761            DiagnosticSeverity::Off
 1762        };
 1763        let style = window.text_style();
 1764        let font_size = style.font_size.to_pixels(window.rem_size());
 1765        let editor = cx.entity().downgrade();
 1766        let fold_placeholder = FoldPlaceholder {
 1767            constrain_width: false,
 1768            render: Arc::new(move |fold_id, fold_range, cx| {
 1769                let editor = editor.clone();
 1770                div()
 1771                    .id(fold_id)
 1772                    .bg(cx.theme().colors().ghost_element_background)
 1773                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1774                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1775                    .rounded_xs()
 1776                    .size_full()
 1777                    .cursor_pointer()
 1778                    .child("")
 1779                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1780                    .on_click(move |_, _window, cx| {
 1781                        editor
 1782                            .update(cx, |editor, cx| {
 1783                                editor.unfold_ranges(
 1784                                    &[fold_range.start..fold_range.end],
 1785                                    true,
 1786                                    false,
 1787                                    cx,
 1788                                );
 1789                                cx.stop_propagation();
 1790                            })
 1791                            .ok();
 1792                    })
 1793                    .into_any()
 1794            }),
 1795            merge_adjacent: true,
 1796            ..FoldPlaceholder::default()
 1797        };
 1798        let display_map = display_map.unwrap_or_else(|| {
 1799            cx.new(|cx| {
 1800                DisplayMap::new(
 1801                    multi_buffer.clone(),
 1802                    style.font(),
 1803                    font_size,
 1804                    None,
 1805                    FILE_HEADER_HEIGHT,
 1806                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1807                    fold_placeholder,
 1808                    diagnostics_max_severity,
 1809                    cx,
 1810                )
 1811            })
 1812        });
 1813
 1814        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1815
 1816        let blink_manager = cx.new(|cx| {
 1817            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1818            if is_minimap {
 1819                blink_manager.disable(cx);
 1820            }
 1821            blink_manager
 1822        });
 1823
 1824        let soft_wrap_mode_override =
 1825            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1826
 1827        let mut project_subscriptions = Vec::new();
 1828        if full_mode && let Some(project) = project.as_ref() {
 1829            project_subscriptions.push(cx.subscribe_in(
 1830                project,
 1831                window,
 1832                |editor, _, event, window, cx| match event {
 1833                    project::Event::RefreshCodeLens => {
 1834                        // we always query lens with actions, without storing them, always refreshing them
 1835                    }
 1836                    project::Event::RefreshInlayHints(server_id) => {
 1837                        editor.refresh_inlay_hints(
 1838                            InlayHintRefreshReason::RefreshRequested(*server_id),
 1839                            cx,
 1840                        );
 1841                    }
 1842                    project::Event::LanguageServerRemoved(..) => {
 1843                        if editor.tasks_update_task.is_none() {
 1844                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1845                        }
 1846                        editor.registered_buffers.clear();
 1847                        editor.register_visible_buffers(cx);
 1848                    }
 1849                    project::Event::LanguageServerAdded(..) => {
 1850                        if editor.tasks_update_task.is_none() {
 1851                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1852                        }
 1853                    }
 1854                    project::Event::SnippetEdit(id, snippet_edits) => {
 1855                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1856                            let focus_handle = editor.focus_handle(cx);
 1857                            if focus_handle.is_focused(window) {
 1858                                let snapshot = buffer.read(cx).snapshot();
 1859                                for (range, snippet) in snippet_edits {
 1860                                    let editor_range =
 1861                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1862                                    editor
 1863                                        .insert_snippet(
 1864                                            &[editor_range],
 1865                                            snippet.clone(),
 1866                                            window,
 1867                                            cx,
 1868                                        )
 1869                                        .ok();
 1870                                }
 1871                            }
 1872                        }
 1873                    }
 1874                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1875                        let buffer_id = *buffer_id;
 1876                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1877                            editor.register_buffer(buffer_id, cx);
 1878                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1879                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1880                            refresh_linked_ranges(editor, window, cx);
 1881                            editor.refresh_code_actions(window, cx);
 1882                            editor.refresh_document_highlights(cx);
 1883                        }
 1884                    }
 1885
 1886                    project::Event::EntryRenamed(transaction) => {
 1887                        let Some(workspace) = editor.workspace() else {
 1888                            return;
 1889                        };
 1890                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1891                        else {
 1892                            return;
 1893                        };
 1894                        if active_editor.entity_id() == cx.entity_id() {
 1895                            let edited_buffers_already_open = {
 1896                                let other_editors: Vec<Entity<Editor>> = workspace
 1897                                    .read(cx)
 1898                                    .panes()
 1899                                    .iter()
 1900                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1901                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1902                                    .collect();
 1903
 1904                                transaction.0.keys().all(|buffer| {
 1905                                    other_editors.iter().any(|editor| {
 1906                                        let multi_buffer = editor.read(cx).buffer();
 1907                                        multi_buffer.read(cx).is_singleton()
 1908                                            && multi_buffer.read(cx).as_singleton().map_or(
 1909                                                false,
 1910                                                |singleton| {
 1911                                                    singleton.entity_id() == buffer.entity_id()
 1912                                                },
 1913                                            )
 1914                                    })
 1915                                })
 1916                            };
 1917
 1918                            if !edited_buffers_already_open {
 1919                                let workspace = workspace.downgrade();
 1920                                let transaction = transaction.clone();
 1921                                cx.defer_in(window, move |_, window, cx| {
 1922                                    cx.spawn_in(window, async move |editor, cx| {
 1923                                        Self::open_project_transaction(
 1924                                            &editor,
 1925                                            workspace,
 1926                                            transaction,
 1927                                            "Rename".to_string(),
 1928                                            cx,
 1929                                        )
 1930                                        .await
 1931                                        .ok()
 1932                                    })
 1933                                    .detach();
 1934                                });
 1935                            }
 1936                        }
 1937                    }
 1938
 1939                    _ => {}
 1940                },
 1941            ));
 1942            if let Some(task_inventory) = project
 1943                .read(cx)
 1944                .task_store()
 1945                .read(cx)
 1946                .task_inventory()
 1947                .cloned()
 1948            {
 1949                project_subscriptions.push(cx.observe_in(
 1950                    &task_inventory,
 1951                    window,
 1952                    |editor, _, window, cx| {
 1953                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1954                    },
 1955                ));
 1956            };
 1957
 1958            project_subscriptions.push(cx.subscribe_in(
 1959                &project.read(cx).breakpoint_store(),
 1960                window,
 1961                |editor, _, event, window, cx| match event {
 1962                    BreakpointStoreEvent::ClearDebugLines => {
 1963                        editor.clear_row_highlights::<ActiveDebugLine>();
 1964                        editor.refresh_inline_values(cx);
 1965                    }
 1966                    BreakpointStoreEvent::SetDebugLine => {
 1967                        if editor.go_to_active_debug_line(window, cx) {
 1968                            cx.stop_propagation();
 1969                        }
 1970
 1971                        editor.refresh_inline_values(cx);
 1972                    }
 1973                    _ => {}
 1974                },
 1975            ));
 1976            let git_store = project.read(cx).git_store().clone();
 1977            let project = project.clone();
 1978            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1979                if let GitStoreEvent::RepositoryAdded = event {
 1980                    this.load_diff_task = Some(
 1981                        update_uncommitted_diff_for_buffer(
 1982                            cx.entity(),
 1983                            &project,
 1984                            this.buffer.read(cx).all_buffers(),
 1985                            this.buffer.clone(),
 1986                            cx,
 1987                        )
 1988                        .shared(),
 1989                    );
 1990                }
 1991            }));
 1992        }
 1993
 1994        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 1995
 1996        let inlay_hint_settings =
 1997            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1998        let focus_handle = cx.focus_handle();
 1999        if !is_minimap {
 2000            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2001                .detach();
 2002            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2003                .detach();
 2004            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2005                .detach();
 2006            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2007                .detach();
 2008            cx.observe_pending_input(window, Self::observe_pending_input)
 2009                .detach();
 2010        }
 2011
 2012        let show_indent_guides =
 2013            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2014                Some(false)
 2015            } else {
 2016                None
 2017            };
 2018
 2019        let breakpoint_store = match (&mode, project.as_ref()) {
 2020            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2021            _ => None,
 2022        };
 2023
 2024        let mut code_action_providers = Vec::new();
 2025        let mut load_uncommitted_diff = None;
 2026        if let Some(project) = project.clone() {
 2027            load_uncommitted_diff = Some(
 2028                update_uncommitted_diff_for_buffer(
 2029                    cx.entity(),
 2030                    &project,
 2031                    multi_buffer.read(cx).all_buffers(),
 2032                    multi_buffer.clone(),
 2033                    cx,
 2034                )
 2035                .shared(),
 2036            );
 2037            code_action_providers.push(Rc::new(project) as Rc<_>);
 2038        }
 2039
 2040        let mut editor = Self {
 2041            focus_handle,
 2042            show_cursor_when_unfocused: false,
 2043            last_focused_descendant: None,
 2044            buffer: multi_buffer.clone(),
 2045            display_map: display_map.clone(),
 2046            placeholder_display_map: None,
 2047            selections,
 2048            scroll_manager: ScrollManager::new(cx),
 2049            columnar_selection_state: None,
 2050            add_selections_state: None,
 2051            select_next_state: None,
 2052            select_prev_state: None,
 2053            selection_history: SelectionHistory::default(),
 2054            defer_selection_effects: false,
 2055            deferred_selection_effects_state: None,
 2056            autoclose_regions: Vec::new(),
 2057            snippet_stack: InvalidationStack::default(),
 2058            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2059            ime_transaction: None,
 2060            active_diagnostics: ActiveDiagnostic::None,
 2061            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2062            inline_diagnostics_update: Task::ready(()),
 2063            inline_diagnostics: Vec::new(),
 2064            soft_wrap_mode_override,
 2065            diagnostics_max_severity,
 2066            hard_wrap: None,
 2067            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2068            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2069            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2070            project,
 2071            blink_manager: blink_manager.clone(),
 2072            show_local_selections: true,
 2073            show_scrollbars: ScrollbarAxes {
 2074                horizontal: full_mode,
 2075                vertical: full_mode,
 2076            },
 2077            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2078            offset_content: !matches!(mode, EditorMode::SingleLine),
 2079            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2080            show_gutter: full_mode,
 2081            show_line_numbers: (!full_mode).then_some(false),
 2082            use_relative_line_numbers: None,
 2083            disable_expand_excerpt_buttons: !full_mode,
 2084            show_git_diff_gutter: None,
 2085            show_code_actions: None,
 2086            show_runnables: None,
 2087            show_breakpoints: None,
 2088            show_wrap_guides: None,
 2089            show_indent_guides,
 2090            highlight_order: 0,
 2091            highlighted_rows: HashMap::default(),
 2092            background_highlights: HashMap::default(),
 2093            gutter_highlights: HashMap::default(),
 2094            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2095            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2096            nav_history: None,
 2097            context_menu: RefCell::new(None),
 2098            context_menu_options: None,
 2099            mouse_context_menu: None,
 2100            completion_tasks: Vec::new(),
 2101            inline_blame_popover: None,
 2102            inline_blame_popover_show_task: None,
 2103            signature_help_state: SignatureHelpState::default(),
 2104            auto_signature_help: None,
 2105            find_all_references_task_sources: Vec::new(),
 2106            next_completion_id: 0,
 2107            next_inlay_id: 0,
 2108            code_action_providers,
 2109            available_code_actions: None,
 2110            code_actions_task: None,
 2111            quick_selection_highlight_task: None,
 2112            debounced_selection_highlight_task: None,
 2113            document_highlights_task: None,
 2114            linked_editing_range_task: None,
 2115            pending_rename: None,
 2116            searchable: !is_minimap,
 2117            cursor_shape: EditorSettings::get_global(cx)
 2118                .cursor_shape
 2119                .unwrap_or_default(),
 2120            current_line_highlight: None,
 2121            autoindent_mode: Some(AutoindentMode::EachLine),
 2122            collapse_matches: false,
 2123            workspace: None,
 2124            input_enabled: !is_minimap,
 2125            use_modal_editing: full_mode,
 2126            read_only: is_minimap,
 2127            use_autoclose: true,
 2128            use_auto_surround: true,
 2129            auto_replace_emoji_shortcode: false,
 2130            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2131            leader_id: None,
 2132            remote_id: None,
 2133            hover_state: HoverState::default(),
 2134            pending_mouse_down: None,
 2135            hovered_link_state: None,
 2136            edit_prediction_provider: None,
 2137            active_edit_prediction: None,
 2138            stale_edit_prediction_in_menu: None,
 2139            edit_prediction_preview: EditPredictionPreview::Inactive {
 2140                released_too_fast: false,
 2141            },
 2142            inline_diagnostics_enabled: full_mode,
 2143            diagnostics_enabled: full_mode,
 2144            word_completions_enabled: full_mode,
 2145            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2146            gutter_hovered: false,
 2147            pixel_position_of_newest_cursor: None,
 2148            last_bounds: None,
 2149            last_position_map: None,
 2150            expect_bounds_change: None,
 2151            gutter_dimensions: GutterDimensions::default(),
 2152            style: None,
 2153            show_cursor_names: false,
 2154            hovered_cursors: HashMap::default(),
 2155            next_editor_action_id: EditorActionId::default(),
 2156            editor_actions: Rc::default(),
 2157            edit_predictions_hidden_for_vim_mode: false,
 2158            show_edit_predictions_override: None,
 2159            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2160            edit_prediction_settings: EditPredictionSettings::Disabled,
 2161            edit_prediction_indent_conflict: false,
 2162            edit_prediction_requires_modifier_in_indent_conflict: true,
 2163            custom_context_menu: None,
 2164            show_git_blame_gutter: false,
 2165            show_git_blame_inline: false,
 2166            show_selection_menu: None,
 2167            show_git_blame_inline_delay_task: None,
 2168            git_blame_inline_enabled: full_mode
 2169                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2170            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2171            serialize_dirty_buffers: !is_minimap
 2172                && ProjectSettings::get_global(cx)
 2173                    .session
 2174                    .restore_unsaved_buffers,
 2175            blame: None,
 2176            blame_subscription: None,
 2177            tasks: BTreeMap::default(),
 2178
 2179            breakpoint_store,
 2180            gutter_breakpoint_indicator: (None, None),
 2181            hovered_diff_hunk_row: None,
 2182            _subscriptions: (!is_minimap)
 2183                .then(|| {
 2184                    vec![
 2185                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2186                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2187                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2188                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2189                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2190                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2191                        cx.observe_window_activation(window, |editor, window, cx| {
 2192                            let active = window.is_window_active();
 2193                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2194                                if active {
 2195                                    blink_manager.enable(cx);
 2196                                } else {
 2197                                    blink_manager.disable(cx);
 2198                                }
 2199                            });
 2200                            if active {
 2201                                editor.show_mouse_cursor(cx);
 2202                            }
 2203                        }),
 2204                    ]
 2205                })
 2206                .unwrap_or_default(),
 2207            tasks_update_task: None,
 2208            pull_diagnostics_task: Task::ready(()),
 2209            colors: None,
 2210            refresh_colors_task: Task::ready(()),
 2211            inlay_hints: None,
 2212            next_color_inlay_id: 0,
 2213            post_scroll_update: Task::ready(()),
 2214            linked_edit_ranges: Default::default(),
 2215            in_project_search: false,
 2216            previous_search_ranges: None,
 2217            breadcrumb_header: None,
 2218            focused_block: None,
 2219            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2220            addons: HashMap::default(),
 2221            registered_buffers: HashMap::default(),
 2222            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2223            selection_mark_mode: false,
 2224            toggle_fold_multiple_buffers: Task::ready(()),
 2225            serialize_selections: Task::ready(()),
 2226            serialize_folds: Task::ready(()),
 2227            text_style_refinement: None,
 2228            load_diff_task: load_uncommitted_diff,
 2229            temporary_diff_override: false,
 2230            mouse_cursor_hidden: false,
 2231            minimap: None,
 2232            hide_mouse_mode: EditorSettings::get_global(cx)
 2233                .hide_mouse
 2234                .unwrap_or_default(),
 2235            change_list: ChangeList::new(),
 2236            mode,
 2237            selection_drag_state: SelectionDragState::None,
 2238            folding_newlines: Task::ready(()),
 2239            lookup_key: None,
 2240        };
 2241
 2242        if is_minimap {
 2243            return editor;
 2244        }
 2245
 2246        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2247            editor
 2248                ._subscriptions
 2249                .push(cx.observe(breakpoints, |_, _, cx| {
 2250                    cx.notify();
 2251                }));
 2252        }
 2253        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2254        editor._subscriptions.extend(project_subscriptions);
 2255
 2256        editor._subscriptions.push(cx.subscribe_in(
 2257            &cx.entity(),
 2258            window,
 2259            |editor, _, e: &EditorEvent, window, cx| match e {
 2260                EditorEvent::ScrollPositionChanged { local, .. } => {
 2261                    if *local {
 2262                        let new_anchor = editor.scroll_manager.anchor();
 2263                        let snapshot = editor.snapshot(window, cx);
 2264                        editor.update_restoration_data(cx, move |data| {
 2265                            data.scroll_position = (
 2266                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2267                                new_anchor.offset,
 2268                            );
 2269                        });
 2270                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2271                        editor.inline_blame_popover.take();
 2272                    }
 2273                }
 2274                EditorEvent::Edited { .. } => {
 2275                    if !vim_enabled(cx) {
 2276                        let display_map = editor.display_snapshot(cx);
 2277                        let selections = editor.selections.all_adjusted_display(&display_map);
 2278                        let pop_state = editor
 2279                            .change_list
 2280                            .last()
 2281                            .map(|previous| {
 2282                                previous.len() == selections.len()
 2283                                    && previous.iter().enumerate().all(|(ix, p)| {
 2284                                        p.to_display_point(&display_map).row()
 2285                                            == selections[ix].head().row()
 2286                                    })
 2287                            })
 2288                            .unwrap_or(false);
 2289                        let new_positions = selections
 2290                            .into_iter()
 2291                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2292                            .collect();
 2293                        editor
 2294                            .change_list
 2295                            .push_to_change_list(pop_state, new_positions);
 2296                    }
 2297                }
 2298                _ => (),
 2299            },
 2300        ));
 2301
 2302        if let Some(dap_store) = editor
 2303            .project
 2304            .as_ref()
 2305            .map(|project| project.read(cx).dap_store())
 2306        {
 2307            let weak_editor = cx.weak_entity();
 2308
 2309            editor
 2310                ._subscriptions
 2311                .push(
 2312                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2313                        let session_entity = cx.entity();
 2314                        weak_editor
 2315                            .update(cx, |editor, cx| {
 2316                                editor._subscriptions.push(
 2317                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2318                                );
 2319                            })
 2320                            .ok();
 2321                    }),
 2322                );
 2323
 2324            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2325                editor
 2326                    ._subscriptions
 2327                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2328            }
 2329        }
 2330
 2331        // skip adding the initial selection to selection history
 2332        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2333        editor.end_selection(window, cx);
 2334        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2335
 2336        editor.scroll_manager.show_scrollbars(window, cx);
 2337        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2338
 2339        if full_mode {
 2340            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2341            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2342
 2343            if editor.git_blame_inline_enabled {
 2344                editor.start_git_blame_inline(false, window, cx);
 2345            }
 2346
 2347            editor.go_to_active_debug_line(window, cx);
 2348
 2349            editor.minimap =
 2350                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2351            editor.colors = Some(LspColorData::new(cx));
 2352            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2353
 2354            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2355                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2356            }
 2357            editor.update_lsp_data(None, window, cx);
 2358            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2359        }
 2360
 2361        editor
 2362    }
 2363
 2364    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2365        self.selections.display_map(cx)
 2366    }
 2367
 2368    pub fn deploy_mouse_context_menu(
 2369        &mut self,
 2370        position: gpui::Point<Pixels>,
 2371        context_menu: Entity<ContextMenu>,
 2372        window: &mut Window,
 2373        cx: &mut Context<Self>,
 2374    ) {
 2375        self.mouse_context_menu = Some(MouseContextMenu::new(
 2376            self,
 2377            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2378            context_menu,
 2379            window,
 2380            cx,
 2381        ));
 2382    }
 2383
 2384    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2385        self.mouse_context_menu
 2386            .as_ref()
 2387            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2388    }
 2389
 2390    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2391        if self
 2392            .selections
 2393            .pending_anchor()
 2394            .is_some_and(|pending_selection| {
 2395                let snapshot = self.buffer().read(cx).snapshot(cx);
 2396                pending_selection.range().includes(range, &snapshot)
 2397            })
 2398        {
 2399            return true;
 2400        }
 2401
 2402        self.selections
 2403            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2404            .into_iter()
 2405            .any(|selection| {
 2406                // This is needed to cover a corner case, if we just check for an existing
 2407                // selection in the fold range, having a cursor at the start of the fold
 2408                // marks it as selected. Non-empty selections don't cause this.
 2409                let length = selection.end - selection.start;
 2410                length > 0
 2411            })
 2412    }
 2413
 2414    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2415        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2416    }
 2417
 2418    fn key_context_internal(
 2419        &self,
 2420        has_active_edit_prediction: bool,
 2421        window: &mut Window,
 2422        cx: &mut App,
 2423    ) -> KeyContext {
 2424        let mut key_context = KeyContext::new_with_defaults();
 2425        key_context.add("Editor");
 2426        let mode = match self.mode {
 2427            EditorMode::SingleLine => "single_line",
 2428            EditorMode::AutoHeight { .. } => "auto_height",
 2429            EditorMode::Minimap { .. } => "minimap",
 2430            EditorMode::Full { .. } => "full",
 2431        };
 2432
 2433        if EditorSettings::jupyter_enabled(cx) {
 2434            key_context.add("jupyter");
 2435        }
 2436
 2437        key_context.set("mode", mode);
 2438        if self.pending_rename.is_some() {
 2439            key_context.add("renaming");
 2440        }
 2441
 2442        match self.context_menu.borrow().as_ref() {
 2443            Some(CodeContextMenu::Completions(menu)) => {
 2444                if menu.visible() {
 2445                    key_context.add("menu");
 2446                    key_context.add("showing_completions");
 2447                }
 2448            }
 2449            Some(CodeContextMenu::CodeActions(menu)) => {
 2450                if menu.visible() {
 2451                    key_context.add("menu");
 2452                    key_context.add("showing_code_actions")
 2453                }
 2454            }
 2455            None => {}
 2456        }
 2457
 2458        if self.signature_help_state.has_multiple_signatures() {
 2459            key_context.add("showing_signature_help");
 2460        }
 2461
 2462        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2463        if !self.focus_handle(cx).contains_focused(window, cx)
 2464            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2465        {
 2466            for addon in self.addons.values() {
 2467                addon.extend_key_context(&mut key_context, cx)
 2468            }
 2469        }
 2470
 2471        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2472            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2473                Some(
 2474                    file.full_path(cx)
 2475                        .extension()?
 2476                        .to_string_lossy()
 2477                        .into_owned(),
 2478                )
 2479            }) {
 2480                key_context.set("extension", extension);
 2481            }
 2482        } else {
 2483            key_context.add("multibuffer");
 2484        }
 2485
 2486        if has_active_edit_prediction {
 2487            if self.edit_prediction_in_conflict() {
 2488                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2489            } else {
 2490                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2491                key_context.add("copilot_suggestion");
 2492            }
 2493        }
 2494
 2495        if self.selection_mark_mode {
 2496            key_context.add("selection_mode");
 2497        }
 2498
 2499        let disjoint = self.selections.disjoint_anchors();
 2500        let snapshot = self.snapshot(window, cx);
 2501        let snapshot = snapshot.buffer_snapshot();
 2502        if self.mode == EditorMode::SingleLine
 2503            && let [selection] = disjoint
 2504            && selection.start == selection.end
 2505            && selection.end.to_offset(snapshot) == snapshot.len()
 2506        {
 2507            key_context.add("end_of_input");
 2508        }
 2509
 2510        key_context
 2511    }
 2512
 2513    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2514        self.last_bounds.as_ref()
 2515    }
 2516
 2517    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2518        if self.mouse_cursor_hidden {
 2519            self.mouse_cursor_hidden = false;
 2520            cx.notify();
 2521        }
 2522    }
 2523
 2524    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2525        let hide_mouse_cursor = match origin {
 2526            HideMouseCursorOrigin::TypingAction => {
 2527                matches!(
 2528                    self.hide_mouse_mode,
 2529                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2530                )
 2531            }
 2532            HideMouseCursorOrigin::MovementAction => {
 2533                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2534            }
 2535        };
 2536        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2537            self.mouse_cursor_hidden = hide_mouse_cursor;
 2538            cx.notify();
 2539        }
 2540    }
 2541
 2542    pub fn edit_prediction_in_conflict(&self) -> bool {
 2543        if !self.show_edit_predictions_in_menu() {
 2544            return false;
 2545        }
 2546
 2547        let showing_completions = self
 2548            .context_menu
 2549            .borrow()
 2550            .as_ref()
 2551            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2552
 2553        showing_completions
 2554            || self.edit_prediction_requires_modifier()
 2555            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2556            // bindings to insert tab characters.
 2557            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2558    }
 2559
 2560    pub fn accept_edit_prediction_keybind(
 2561        &self,
 2562        accept_partial: bool,
 2563        window: &mut Window,
 2564        cx: &mut App,
 2565    ) -> AcceptEditPredictionBinding {
 2566        let key_context = self.key_context_internal(true, window, cx);
 2567        let in_conflict = self.edit_prediction_in_conflict();
 2568
 2569        let bindings = if accept_partial {
 2570            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2571        } else {
 2572            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2573        };
 2574
 2575        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2576        // just the first one.
 2577        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2578            !in_conflict
 2579                || binding
 2580                    .keystrokes()
 2581                    .first()
 2582                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2583        }))
 2584    }
 2585
 2586    pub fn new_file(
 2587        workspace: &mut Workspace,
 2588        _: &workspace::NewFile,
 2589        window: &mut Window,
 2590        cx: &mut Context<Workspace>,
 2591    ) {
 2592        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2593            "Failed to create buffer",
 2594            window,
 2595            cx,
 2596            |e, _, _| match e.error_code() {
 2597                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2598                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2599                e.error_tag("required").unwrap_or("the latest version")
 2600            )),
 2601                _ => None,
 2602            },
 2603        );
 2604    }
 2605
 2606    pub fn new_in_workspace(
 2607        workspace: &mut Workspace,
 2608        window: &mut Window,
 2609        cx: &mut Context<Workspace>,
 2610    ) -> Task<Result<Entity<Editor>>> {
 2611        let project = workspace.project().clone();
 2612        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2613
 2614        cx.spawn_in(window, async move |workspace, cx| {
 2615            let buffer = create.await?;
 2616            workspace.update_in(cx, |workspace, window, cx| {
 2617                let editor =
 2618                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2619                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2620                editor
 2621            })
 2622        })
 2623    }
 2624
 2625    fn new_file_vertical(
 2626        workspace: &mut Workspace,
 2627        _: &workspace::NewFileSplitVertical,
 2628        window: &mut Window,
 2629        cx: &mut Context<Workspace>,
 2630    ) {
 2631        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2632    }
 2633
 2634    fn new_file_horizontal(
 2635        workspace: &mut Workspace,
 2636        _: &workspace::NewFileSplitHorizontal,
 2637        window: &mut Window,
 2638        cx: &mut Context<Workspace>,
 2639    ) {
 2640        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2641    }
 2642
 2643    fn new_file_split(
 2644        workspace: &mut Workspace,
 2645        action: &workspace::NewFileSplit,
 2646        window: &mut Window,
 2647        cx: &mut Context<Workspace>,
 2648    ) {
 2649        Self::new_file_in_direction(workspace, action.0, window, cx)
 2650    }
 2651
 2652    fn new_file_in_direction(
 2653        workspace: &mut Workspace,
 2654        direction: SplitDirection,
 2655        window: &mut Window,
 2656        cx: &mut Context<Workspace>,
 2657    ) {
 2658        let project = workspace.project().clone();
 2659        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2660
 2661        cx.spawn_in(window, async move |workspace, cx| {
 2662            let buffer = create.await?;
 2663            workspace.update_in(cx, move |workspace, window, cx| {
 2664                workspace.split_item(
 2665                    direction,
 2666                    Box::new(
 2667                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2668                    ),
 2669                    window,
 2670                    cx,
 2671                )
 2672            })?;
 2673            anyhow::Ok(())
 2674        })
 2675        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2676            match e.error_code() {
 2677                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2678                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2679                e.error_tag("required").unwrap_or("the latest version")
 2680            )),
 2681                _ => None,
 2682            }
 2683        });
 2684    }
 2685
 2686    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2687        self.leader_id
 2688    }
 2689
 2690    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2691        &self.buffer
 2692    }
 2693
 2694    pub fn project(&self) -> Option<&Entity<Project>> {
 2695        self.project.as_ref()
 2696    }
 2697
 2698    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2699        self.workspace.as_ref()?.0.upgrade()
 2700    }
 2701
 2702    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2703        self.buffer().read(cx).title(cx)
 2704    }
 2705
 2706    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2707        let git_blame_gutter_max_author_length = self
 2708            .render_git_blame_gutter(cx)
 2709            .then(|| {
 2710                if let Some(blame) = self.blame.as_ref() {
 2711                    let max_author_length =
 2712                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2713                    Some(max_author_length)
 2714                } else {
 2715                    None
 2716                }
 2717            })
 2718            .flatten();
 2719
 2720        EditorSnapshot {
 2721            mode: self.mode.clone(),
 2722            show_gutter: self.show_gutter,
 2723            show_line_numbers: self.show_line_numbers,
 2724            show_git_diff_gutter: self.show_git_diff_gutter,
 2725            show_code_actions: self.show_code_actions,
 2726            show_runnables: self.show_runnables,
 2727            show_breakpoints: self.show_breakpoints,
 2728            git_blame_gutter_max_author_length,
 2729            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2730            placeholder_display_snapshot: self
 2731                .placeholder_display_map
 2732                .as_ref()
 2733                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2734            scroll_anchor: self.scroll_manager.anchor(),
 2735            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2736            is_focused: self.focus_handle.is_focused(window),
 2737            current_line_highlight: self
 2738                .current_line_highlight
 2739                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2740            gutter_hovered: self.gutter_hovered,
 2741        }
 2742    }
 2743
 2744    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2745        self.buffer.read(cx).language_at(point, cx)
 2746    }
 2747
 2748    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2749        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2750    }
 2751
 2752    pub fn active_excerpt(
 2753        &self,
 2754        cx: &App,
 2755    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2756        self.buffer
 2757            .read(cx)
 2758            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2759    }
 2760
 2761    pub fn mode(&self) -> &EditorMode {
 2762        &self.mode
 2763    }
 2764
 2765    pub fn set_mode(&mut self, mode: EditorMode) {
 2766        self.mode = mode;
 2767    }
 2768
 2769    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2770        self.collaboration_hub.as_deref()
 2771    }
 2772
 2773    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2774        self.collaboration_hub = Some(hub);
 2775    }
 2776
 2777    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2778        self.in_project_search = in_project_search;
 2779    }
 2780
 2781    pub fn set_custom_context_menu(
 2782        &mut self,
 2783        f: impl 'static
 2784        + Fn(
 2785            &mut Self,
 2786            DisplayPoint,
 2787            &mut Window,
 2788            &mut Context<Self>,
 2789        ) -> Option<Entity<ui::ContextMenu>>,
 2790    ) {
 2791        self.custom_context_menu = Some(Box::new(f))
 2792    }
 2793
 2794    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2795        self.completion_provider = provider;
 2796    }
 2797
 2798    #[cfg(any(test, feature = "test-support"))]
 2799    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2800        self.completion_provider.clone()
 2801    }
 2802
 2803    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2804        self.semantics_provider.clone()
 2805    }
 2806
 2807    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2808        self.semantics_provider = provider;
 2809    }
 2810
 2811    pub fn set_edit_prediction_provider<T>(
 2812        &mut self,
 2813        provider: Option<Entity<T>>,
 2814        window: &mut Window,
 2815        cx: &mut Context<Self>,
 2816    ) where
 2817        T: EditPredictionProvider,
 2818    {
 2819        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2820            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2821                if this.focus_handle.is_focused(window) {
 2822                    this.update_visible_edit_prediction(window, cx);
 2823                }
 2824            }),
 2825            provider: Arc::new(provider),
 2826        });
 2827        self.update_edit_prediction_settings(cx);
 2828        self.refresh_edit_prediction(false, false, window, cx);
 2829    }
 2830
 2831    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2832        self.placeholder_display_map
 2833            .as_ref()
 2834            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2835    }
 2836
 2837    pub fn set_placeholder_text(
 2838        &mut self,
 2839        placeholder_text: &str,
 2840        window: &mut Window,
 2841        cx: &mut Context<Self>,
 2842    ) {
 2843        let multibuffer = cx
 2844            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2845
 2846        let style = window.text_style();
 2847
 2848        self.placeholder_display_map = Some(cx.new(|cx| {
 2849            DisplayMap::new(
 2850                multibuffer,
 2851                style.font(),
 2852                style.font_size.to_pixels(window.rem_size()),
 2853                None,
 2854                FILE_HEADER_HEIGHT,
 2855                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2856                Default::default(),
 2857                DiagnosticSeverity::Off,
 2858                cx,
 2859            )
 2860        }));
 2861        cx.notify();
 2862    }
 2863
 2864    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2865        self.cursor_shape = cursor_shape;
 2866
 2867        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2868        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2869
 2870        cx.notify();
 2871    }
 2872
 2873    pub fn set_current_line_highlight(
 2874        &mut self,
 2875        current_line_highlight: Option<CurrentLineHighlight>,
 2876    ) {
 2877        self.current_line_highlight = current_line_highlight;
 2878    }
 2879
 2880    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2881        self.collapse_matches = collapse_matches;
 2882    }
 2883
 2884    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2885        if self.collapse_matches {
 2886            return range.start..range.start;
 2887        }
 2888        range.clone()
 2889    }
 2890
 2891    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2892        if self.display_map.read(cx).clip_at_line_ends != clip {
 2893            self.display_map
 2894                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2895        }
 2896    }
 2897
 2898    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2899        self.input_enabled = input_enabled;
 2900    }
 2901
 2902    pub fn set_edit_predictions_hidden_for_vim_mode(
 2903        &mut self,
 2904        hidden: bool,
 2905        window: &mut Window,
 2906        cx: &mut Context<Self>,
 2907    ) {
 2908        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2909            self.edit_predictions_hidden_for_vim_mode = hidden;
 2910            if hidden {
 2911                self.update_visible_edit_prediction(window, cx);
 2912            } else {
 2913                self.refresh_edit_prediction(true, false, window, cx);
 2914            }
 2915        }
 2916    }
 2917
 2918    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2919        self.menu_edit_predictions_policy = value;
 2920    }
 2921
 2922    pub fn set_autoindent(&mut self, autoindent: bool) {
 2923        if autoindent {
 2924            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2925        } else {
 2926            self.autoindent_mode = None;
 2927        }
 2928    }
 2929
 2930    pub fn read_only(&self, cx: &App) -> bool {
 2931        self.read_only || self.buffer.read(cx).read_only()
 2932    }
 2933
 2934    pub fn set_read_only(&mut self, read_only: bool) {
 2935        self.read_only = read_only;
 2936    }
 2937
 2938    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2939        self.use_autoclose = autoclose;
 2940    }
 2941
 2942    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2943        self.use_auto_surround = auto_surround;
 2944    }
 2945
 2946    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2947        self.auto_replace_emoji_shortcode = auto_replace;
 2948    }
 2949
 2950    pub fn toggle_edit_predictions(
 2951        &mut self,
 2952        _: &ToggleEditPrediction,
 2953        window: &mut Window,
 2954        cx: &mut Context<Self>,
 2955    ) {
 2956        if self.show_edit_predictions_override.is_some() {
 2957            self.set_show_edit_predictions(None, window, cx);
 2958        } else {
 2959            let show_edit_predictions = !self.edit_predictions_enabled();
 2960            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2961        }
 2962    }
 2963
 2964    pub fn set_show_edit_predictions(
 2965        &mut self,
 2966        show_edit_predictions: Option<bool>,
 2967        window: &mut Window,
 2968        cx: &mut Context<Self>,
 2969    ) {
 2970        self.show_edit_predictions_override = show_edit_predictions;
 2971        self.update_edit_prediction_settings(cx);
 2972
 2973        if let Some(false) = show_edit_predictions {
 2974            self.discard_edit_prediction(false, cx);
 2975        } else {
 2976            self.refresh_edit_prediction(false, true, window, cx);
 2977        }
 2978    }
 2979
 2980    fn edit_predictions_disabled_in_scope(
 2981        &self,
 2982        buffer: &Entity<Buffer>,
 2983        buffer_position: language::Anchor,
 2984        cx: &App,
 2985    ) -> bool {
 2986        let snapshot = buffer.read(cx).snapshot();
 2987        let settings = snapshot.settings_at(buffer_position, cx);
 2988
 2989        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2990            return false;
 2991        };
 2992
 2993        scope.override_name().is_some_and(|scope_name| {
 2994            settings
 2995                .edit_predictions_disabled_in
 2996                .iter()
 2997                .any(|s| s == scope_name)
 2998        })
 2999    }
 3000
 3001    pub fn set_use_modal_editing(&mut self, to: bool) {
 3002        self.use_modal_editing = to;
 3003    }
 3004
 3005    pub fn use_modal_editing(&self) -> bool {
 3006        self.use_modal_editing
 3007    }
 3008
 3009    fn selections_did_change(
 3010        &mut self,
 3011        local: bool,
 3012        old_cursor_position: &Anchor,
 3013        effects: SelectionEffects,
 3014        window: &mut Window,
 3015        cx: &mut Context<Self>,
 3016    ) {
 3017        window.invalidate_character_coordinates();
 3018
 3019        // Copy selections to primary selection buffer
 3020        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3021        if local {
 3022            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3023            let buffer_handle = self.buffer.read(cx).read(cx);
 3024
 3025            let mut text = String::new();
 3026            for (index, selection) in selections.iter().enumerate() {
 3027                let text_for_selection = buffer_handle
 3028                    .text_for_range(selection.start..selection.end)
 3029                    .collect::<String>();
 3030
 3031                text.push_str(&text_for_selection);
 3032                if index != selections.len() - 1 {
 3033                    text.push('\n');
 3034                }
 3035            }
 3036
 3037            if !text.is_empty() {
 3038                cx.write_to_primary(ClipboardItem::new_string(text));
 3039            }
 3040        }
 3041
 3042        let selection_anchors = self.selections.disjoint_anchors_arc();
 3043
 3044        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3045            self.buffer.update(cx, |buffer, cx| {
 3046                buffer.set_active_selections(
 3047                    &selection_anchors,
 3048                    self.selections.line_mode(),
 3049                    self.cursor_shape,
 3050                    cx,
 3051                )
 3052            });
 3053        }
 3054        let display_map = self
 3055            .display_map
 3056            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3057        let buffer = display_map.buffer_snapshot();
 3058        if self.selections.count() == 1 {
 3059            self.add_selections_state = None;
 3060        }
 3061        self.select_next_state = None;
 3062        self.select_prev_state = None;
 3063        self.select_syntax_node_history.try_clear();
 3064        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3065        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3066        self.take_rename(false, window, cx);
 3067
 3068        let newest_selection = self.selections.newest_anchor();
 3069        let new_cursor_position = newest_selection.head();
 3070        let selection_start = newest_selection.start;
 3071
 3072        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3073            self.push_to_nav_history(
 3074                *old_cursor_position,
 3075                Some(new_cursor_position.to_point(buffer)),
 3076                false,
 3077                effects.nav_history == Some(true),
 3078                cx,
 3079            );
 3080        }
 3081
 3082        if local {
 3083            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3084                self.register_buffer(buffer_id, cx);
 3085            }
 3086
 3087            let mut context_menu = self.context_menu.borrow_mut();
 3088            let completion_menu = match context_menu.as_ref() {
 3089                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3090                Some(CodeContextMenu::CodeActions(_)) => {
 3091                    *context_menu = None;
 3092                    None
 3093                }
 3094                None => None,
 3095            };
 3096            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3097            drop(context_menu);
 3098
 3099            if effects.completions
 3100                && let Some(completion_position) = completion_position
 3101            {
 3102                let start_offset = selection_start.to_offset(buffer);
 3103                let position_matches = start_offset == completion_position.to_offset(buffer);
 3104                let continue_showing = if position_matches {
 3105                    if self.snippet_stack.is_empty() {
 3106                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3107                            == Some(CharKind::Word)
 3108                    } else {
 3109                        // Snippet choices can be shown even when the cursor is in whitespace.
 3110                        // Dismissing the menu with actions like backspace is handled by
 3111                        // invalidation regions.
 3112                        true
 3113                    }
 3114                } else {
 3115                    false
 3116                };
 3117
 3118                if continue_showing {
 3119                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3120                } else {
 3121                    self.hide_context_menu(window, cx);
 3122                }
 3123            }
 3124
 3125            hide_hover(self, cx);
 3126
 3127            if old_cursor_position.to_display_point(&display_map).row()
 3128                != new_cursor_position.to_display_point(&display_map).row()
 3129            {
 3130                self.available_code_actions.take();
 3131            }
 3132            self.refresh_code_actions(window, cx);
 3133            self.refresh_document_highlights(cx);
 3134            refresh_linked_ranges(self, window, cx);
 3135
 3136            self.refresh_selected_text_highlights(false, window, cx);
 3137            self.refresh_matching_bracket_highlights(window, cx);
 3138            self.update_visible_edit_prediction(window, cx);
 3139            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3140            self.inline_blame_popover.take();
 3141            if self.git_blame_inline_enabled {
 3142                self.start_inline_blame_timer(window, cx);
 3143            }
 3144        }
 3145
 3146        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3147        cx.emit(EditorEvent::SelectionsChanged { local });
 3148
 3149        let selections = &self.selections.disjoint_anchors_arc();
 3150        if selections.len() == 1 {
 3151            cx.emit(SearchEvent::ActiveMatchChanged)
 3152        }
 3153        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3154            let inmemory_selections = selections
 3155                .iter()
 3156                .map(|s| {
 3157                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3158                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3159                })
 3160                .collect();
 3161            self.update_restoration_data(cx, |data| {
 3162                data.selections = inmemory_selections;
 3163            });
 3164
 3165            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3166                && let Some(workspace_id) =
 3167                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3168            {
 3169                let snapshot = self.buffer().read(cx).snapshot(cx);
 3170                let selections = selections.clone();
 3171                let background_executor = cx.background_executor().clone();
 3172                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3173                self.serialize_selections = cx.background_spawn(async move {
 3174                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3175                    let db_selections = selections
 3176                        .iter()
 3177                        .map(|selection| {
 3178                            (
 3179                                selection.start.to_offset(&snapshot),
 3180                                selection.end.to_offset(&snapshot),
 3181                            )
 3182                        })
 3183                        .collect();
 3184
 3185                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3186                        .await
 3187                        .with_context(|| {
 3188                            format!(
 3189                                "persisting editor selections for editor {editor_id}, \
 3190                                workspace {workspace_id:?}"
 3191                            )
 3192                        })
 3193                        .log_err();
 3194                });
 3195            }
 3196        }
 3197
 3198        cx.notify();
 3199    }
 3200
 3201    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3202        use text::ToOffset as _;
 3203        use text::ToPoint as _;
 3204
 3205        if self.mode.is_minimap()
 3206            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3207        {
 3208            return;
 3209        }
 3210
 3211        if !self.buffer().read(cx).is_singleton() {
 3212            return;
 3213        }
 3214
 3215        let display_snapshot = self
 3216            .display_map
 3217            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3218        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3219            return;
 3220        };
 3221        let inmemory_folds = display_snapshot
 3222            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3223            .map(|fold| {
 3224                fold.range.start.text_anchor.to_point(&snapshot)
 3225                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3226            })
 3227            .collect();
 3228        self.update_restoration_data(cx, |data| {
 3229            data.folds = inmemory_folds;
 3230        });
 3231
 3232        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3233            return;
 3234        };
 3235        let background_executor = cx.background_executor().clone();
 3236        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3237        let db_folds = display_snapshot
 3238            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3239            .map(|fold| {
 3240                (
 3241                    fold.range.start.text_anchor.to_offset(&snapshot),
 3242                    fold.range.end.text_anchor.to_offset(&snapshot),
 3243                )
 3244            })
 3245            .collect();
 3246        self.serialize_folds = cx.background_spawn(async move {
 3247            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3248            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3249                .await
 3250                .with_context(|| {
 3251                    format!(
 3252                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3253                    )
 3254                })
 3255                .log_err();
 3256        });
 3257    }
 3258
 3259    pub fn sync_selections(
 3260        &mut self,
 3261        other: Entity<Editor>,
 3262        cx: &mut Context<Self>,
 3263    ) -> gpui::Subscription {
 3264        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3265        if !other_selections.is_empty() {
 3266            self.selections.change_with(cx, |selections| {
 3267                selections.select_anchors(other_selections);
 3268            });
 3269        }
 3270
 3271        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3272            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3273                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3274                if other_selections.is_empty() {
 3275                    return;
 3276                }
 3277                this.selections.change_with(cx, |selections| {
 3278                    selections.select_anchors(other_selections);
 3279                });
 3280            }
 3281        });
 3282
 3283        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3284            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3285                let these_selections = this.selections.disjoint_anchors().to_vec();
 3286                if these_selections.is_empty() {
 3287                    return;
 3288                }
 3289                other.update(cx, |other_editor, cx| {
 3290                    other_editor.selections.change_with(cx, |selections| {
 3291                        selections.select_anchors(these_selections);
 3292                    })
 3293                });
 3294            }
 3295        });
 3296
 3297        Subscription::join(other_subscription, this_subscription)
 3298    }
 3299
 3300    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3301    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3302    /// effects of selection change occur at the end of the transaction.
 3303    pub fn change_selections<R>(
 3304        &mut self,
 3305        effects: SelectionEffects,
 3306        window: &mut Window,
 3307        cx: &mut Context<Self>,
 3308        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3309    ) -> R {
 3310        if let Some(state) = &mut self.deferred_selection_effects_state {
 3311            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3312            state.effects.completions = effects.completions;
 3313            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3314            let (changed, result) = self.selections.change_with(cx, change);
 3315            state.changed |= changed;
 3316            return result;
 3317        }
 3318        let mut state = DeferredSelectionEffectsState {
 3319            changed: false,
 3320            effects,
 3321            old_cursor_position: self.selections.newest_anchor().head(),
 3322            history_entry: SelectionHistoryEntry {
 3323                selections: self.selections.disjoint_anchors_arc(),
 3324                select_next_state: self.select_next_state.clone(),
 3325                select_prev_state: self.select_prev_state.clone(),
 3326                add_selections_state: self.add_selections_state.clone(),
 3327            },
 3328        };
 3329        let (changed, result) = self.selections.change_with(cx, change);
 3330        state.changed = state.changed || changed;
 3331        if self.defer_selection_effects {
 3332            self.deferred_selection_effects_state = Some(state);
 3333        } else {
 3334            self.apply_selection_effects(state, window, cx);
 3335        }
 3336        result
 3337    }
 3338
 3339    /// Defers the effects of selection change, so that the effects of multiple calls to
 3340    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3341    /// to selection history and the state of popovers based on selection position aren't
 3342    /// erroneously updated.
 3343    pub fn with_selection_effects_deferred<R>(
 3344        &mut self,
 3345        window: &mut Window,
 3346        cx: &mut Context<Self>,
 3347        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3348    ) -> R {
 3349        let already_deferred = self.defer_selection_effects;
 3350        self.defer_selection_effects = true;
 3351        let result = update(self, window, cx);
 3352        if !already_deferred {
 3353            self.defer_selection_effects = false;
 3354            if let Some(state) = self.deferred_selection_effects_state.take() {
 3355                self.apply_selection_effects(state, window, cx);
 3356            }
 3357        }
 3358        result
 3359    }
 3360
 3361    fn apply_selection_effects(
 3362        &mut self,
 3363        state: DeferredSelectionEffectsState,
 3364        window: &mut Window,
 3365        cx: &mut Context<Self>,
 3366    ) {
 3367        if state.changed {
 3368            self.selection_history.push(state.history_entry);
 3369
 3370            if let Some(autoscroll) = state.effects.scroll {
 3371                self.request_autoscroll(autoscroll, cx);
 3372            }
 3373
 3374            let old_cursor_position = &state.old_cursor_position;
 3375
 3376            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3377
 3378            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3379                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3380            }
 3381        }
 3382    }
 3383
 3384    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3385    where
 3386        I: IntoIterator<Item = (Range<S>, T)>,
 3387        S: ToOffset,
 3388        T: Into<Arc<str>>,
 3389    {
 3390        if self.read_only(cx) {
 3391            return;
 3392        }
 3393
 3394        self.buffer
 3395            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3396    }
 3397
 3398    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3399    where
 3400        I: IntoIterator<Item = (Range<S>, T)>,
 3401        S: ToOffset,
 3402        T: Into<Arc<str>>,
 3403    {
 3404        if self.read_only(cx) {
 3405            return;
 3406        }
 3407
 3408        self.buffer.update(cx, |buffer, cx| {
 3409            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3410        });
 3411    }
 3412
 3413    pub fn edit_with_block_indent<I, S, T>(
 3414        &mut self,
 3415        edits: I,
 3416        original_indent_columns: Vec<Option<u32>>,
 3417        cx: &mut Context<Self>,
 3418    ) where
 3419        I: IntoIterator<Item = (Range<S>, T)>,
 3420        S: ToOffset,
 3421        T: Into<Arc<str>>,
 3422    {
 3423        if self.read_only(cx) {
 3424            return;
 3425        }
 3426
 3427        self.buffer.update(cx, |buffer, cx| {
 3428            buffer.edit(
 3429                edits,
 3430                Some(AutoindentMode::Block {
 3431                    original_indent_columns,
 3432                }),
 3433                cx,
 3434            )
 3435        });
 3436    }
 3437
 3438    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3439        self.hide_context_menu(window, cx);
 3440
 3441        match phase {
 3442            SelectPhase::Begin {
 3443                position,
 3444                add,
 3445                click_count,
 3446            } => self.begin_selection(position, add, click_count, window, cx),
 3447            SelectPhase::BeginColumnar {
 3448                position,
 3449                goal_column,
 3450                reset,
 3451                mode,
 3452            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3453            SelectPhase::Extend {
 3454                position,
 3455                click_count,
 3456            } => self.extend_selection(position, click_count, window, cx),
 3457            SelectPhase::Update {
 3458                position,
 3459                goal_column,
 3460                scroll_delta,
 3461            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3462            SelectPhase::End => self.end_selection(window, cx),
 3463        }
 3464    }
 3465
 3466    fn extend_selection(
 3467        &mut self,
 3468        position: DisplayPoint,
 3469        click_count: usize,
 3470        window: &mut Window,
 3471        cx: &mut Context<Self>,
 3472    ) {
 3473        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3474        let tail = self.selections.newest::<usize>(&display_map).tail();
 3475        let click_count = click_count.max(match self.selections.select_mode() {
 3476            SelectMode::Character => 1,
 3477            SelectMode::Word(_) => 2,
 3478            SelectMode::Line(_) => 3,
 3479            SelectMode::All => 4,
 3480        });
 3481        self.begin_selection(position, false, click_count, window, cx);
 3482
 3483        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3484
 3485        let current_selection = match self.selections.select_mode() {
 3486            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3487            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3488        };
 3489
 3490        let mut pending_selection = self
 3491            .selections
 3492            .pending_anchor()
 3493            .cloned()
 3494            .expect("extend_selection not called with pending selection");
 3495
 3496        if pending_selection
 3497            .start
 3498            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3499            == Ordering::Greater
 3500        {
 3501            pending_selection.start = current_selection.start;
 3502        }
 3503        if pending_selection
 3504            .end
 3505            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3506            == Ordering::Less
 3507        {
 3508            pending_selection.end = current_selection.end;
 3509            pending_selection.reversed = true;
 3510        }
 3511
 3512        let mut pending_mode = self.selections.pending_mode().unwrap();
 3513        match &mut pending_mode {
 3514            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3515            _ => {}
 3516        }
 3517
 3518        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3519            SelectionEffects::scroll(Autoscroll::fit())
 3520        } else {
 3521            SelectionEffects::no_scroll()
 3522        };
 3523
 3524        self.change_selections(effects, window, cx, |s| {
 3525            s.set_pending(pending_selection.clone(), pending_mode);
 3526            s.set_is_extending(true);
 3527        });
 3528    }
 3529
 3530    fn begin_selection(
 3531        &mut self,
 3532        position: DisplayPoint,
 3533        add: bool,
 3534        click_count: usize,
 3535        window: &mut Window,
 3536        cx: &mut Context<Self>,
 3537    ) {
 3538        if !self.focus_handle.is_focused(window) {
 3539            self.last_focused_descendant = None;
 3540            window.focus(&self.focus_handle);
 3541        }
 3542
 3543        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3544        let buffer = display_map.buffer_snapshot();
 3545        let position = display_map.clip_point(position, Bias::Left);
 3546
 3547        let start;
 3548        let end;
 3549        let mode;
 3550        let mut auto_scroll;
 3551        match click_count {
 3552            1 => {
 3553                start = buffer.anchor_before(position.to_point(&display_map));
 3554                end = start;
 3555                mode = SelectMode::Character;
 3556                auto_scroll = true;
 3557            }
 3558            2 => {
 3559                let position = display_map
 3560                    .clip_point(position, Bias::Left)
 3561                    .to_offset(&display_map, Bias::Left);
 3562                let (range, _) = buffer.surrounding_word(position, None);
 3563                start = buffer.anchor_before(range.start);
 3564                end = buffer.anchor_before(range.end);
 3565                mode = SelectMode::Word(start..end);
 3566                auto_scroll = true;
 3567            }
 3568            3 => {
 3569                let position = display_map
 3570                    .clip_point(position, Bias::Left)
 3571                    .to_point(&display_map);
 3572                let line_start = display_map.prev_line_boundary(position).0;
 3573                let next_line_start = buffer.clip_point(
 3574                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3575                    Bias::Left,
 3576                );
 3577                start = buffer.anchor_before(line_start);
 3578                end = buffer.anchor_before(next_line_start);
 3579                mode = SelectMode::Line(start..end);
 3580                auto_scroll = true;
 3581            }
 3582            _ => {
 3583                start = buffer.anchor_before(0);
 3584                end = buffer.anchor_before(buffer.len());
 3585                mode = SelectMode::All;
 3586                auto_scroll = false;
 3587            }
 3588        }
 3589        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3590
 3591        let point_to_delete: Option<usize> = {
 3592            let selected_points: Vec<Selection<Point>> =
 3593                self.selections.disjoint_in_range(start..end, &display_map);
 3594
 3595            if !add || click_count > 1 {
 3596                None
 3597            } else if !selected_points.is_empty() {
 3598                Some(selected_points[0].id)
 3599            } else {
 3600                let clicked_point_already_selected =
 3601                    self.selections.disjoint_anchors().iter().find(|selection| {
 3602                        selection.start.to_point(buffer) == start.to_point(buffer)
 3603                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3604                    });
 3605
 3606                clicked_point_already_selected.map(|selection| selection.id)
 3607            }
 3608        };
 3609
 3610        let selections_count = self.selections.count();
 3611        let effects = if auto_scroll {
 3612            SelectionEffects::default()
 3613        } else {
 3614            SelectionEffects::no_scroll()
 3615        };
 3616
 3617        self.change_selections(effects, window, cx, |s| {
 3618            if let Some(point_to_delete) = point_to_delete {
 3619                s.delete(point_to_delete);
 3620
 3621                if selections_count == 1 {
 3622                    s.set_pending_anchor_range(start..end, mode);
 3623                }
 3624            } else {
 3625                if !add {
 3626                    s.clear_disjoint();
 3627                }
 3628
 3629                s.set_pending_anchor_range(start..end, mode);
 3630            }
 3631        });
 3632    }
 3633
 3634    fn begin_columnar_selection(
 3635        &mut self,
 3636        position: DisplayPoint,
 3637        goal_column: u32,
 3638        reset: bool,
 3639        mode: ColumnarMode,
 3640        window: &mut Window,
 3641        cx: &mut Context<Self>,
 3642    ) {
 3643        if !self.focus_handle.is_focused(window) {
 3644            self.last_focused_descendant = None;
 3645            window.focus(&self.focus_handle);
 3646        }
 3647
 3648        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3649
 3650        if reset {
 3651            let pointer_position = display_map
 3652                .buffer_snapshot()
 3653                .anchor_before(position.to_point(&display_map));
 3654
 3655            self.change_selections(
 3656                SelectionEffects::scroll(Autoscroll::newest()),
 3657                window,
 3658                cx,
 3659                |s| {
 3660                    s.clear_disjoint();
 3661                    s.set_pending_anchor_range(
 3662                        pointer_position..pointer_position,
 3663                        SelectMode::Character,
 3664                    );
 3665                },
 3666            );
 3667        };
 3668
 3669        let tail = self.selections.newest::<Point>(&display_map).tail();
 3670        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3671        self.columnar_selection_state = match mode {
 3672            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3673                selection_tail: selection_anchor,
 3674                display_point: if reset {
 3675                    if position.column() != goal_column {
 3676                        Some(DisplayPoint::new(position.row(), goal_column))
 3677                    } else {
 3678                        None
 3679                    }
 3680                } else {
 3681                    None
 3682                },
 3683            }),
 3684            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3685                selection_tail: selection_anchor,
 3686            }),
 3687        };
 3688
 3689        if !reset {
 3690            self.select_columns(position, goal_column, &display_map, window, cx);
 3691        }
 3692    }
 3693
 3694    fn update_selection(
 3695        &mut self,
 3696        position: DisplayPoint,
 3697        goal_column: u32,
 3698        scroll_delta: gpui::Point<f32>,
 3699        window: &mut Window,
 3700        cx: &mut Context<Self>,
 3701    ) {
 3702        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3703
 3704        if self.columnar_selection_state.is_some() {
 3705            self.select_columns(position, goal_column, &display_map, window, cx);
 3706        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3707            let buffer = display_map.buffer_snapshot();
 3708            let head;
 3709            let tail;
 3710            let mode = self.selections.pending_mode().unwrap();
 3711            match &mode {
 3712                SelectMode::Character => {
 3713                    head = position.to_point(&display_map);
 3714                    tail = pending.tail().to_point(buffer);
 3715                }
 3716                SelectMode::Word(original_range) => {
 3717                    let offset = display_map
 3718                        .clip_point(position, Bias::Left)
 3719                        .to_offset(&display_map, Bias::Left);
 3720                    let original_range = original_range.to_offset(buffer);
 3721
 3722                    let head_offset = if buffer.is_inside_word(offset, None)
 3723                        || original_range.contains(&offset)
 3724                    {
 3725                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3726                        if word_range.start < original_range.start {
 3727                            word_range.start
 3728                        } else {
 3729                            word_range.end
 3730                        }
 3731                    } else {
 3732                        offset
 3733                    };
 3734
 3735                    head = head_offset.to_point(buffer);
 3736                    if head_offset <= original_range.start {
 3737                        tail = original_range.end.to_point(buffer);
 3738                    } else {
 3739                        tail = original_range.start.to_point(buffer);
 3740                    }
 3741                }
 3742                SelectMode::Line(original_range) => {
 3743                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3744
 3745                    let position = display_map
 3746                        .clip_point(position, Bias::Left)
 3747                        .to_point(&display_map);
 3748                    let line_start = display_map.prev_line_boundary(position).0;
 3749                    let next_line_start = buffer.clip_point(
 3750                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3751                        Bias::Left,
 3752                    );
 3753
 3754                    if line_start < original_range.start {
 3755                        head = line_start
 3756                    } else {
 3757                        head = next_line_start
 3758                    }
 3759
 3760                    if head <= original_range.start {
 3761                        tail = original_range.end;
 3762                    } else {
 3763                        tail = original_range.start;
 3764                    }
 3765                }
 3766                SelectMode::All => {
 3767                    return;
 3768                }
 3769            };
 3770
 3771            if head < tail {
 3772                pending.start = buffer.anchor_before(head);
 3773                pending.end = buffer.anchor_before(tail);
 3774                pending.reversed = true;
 3775            } else {
 3776                pending.start = buffer.anchor_before(tail);
 3777                pending.end = buffer.anchor_before(head);
 3778                pending.reversed = false;
 3779            }
 3780
 3781            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3782                s.set_pending(pending.clone(), mode);
 3783            });
 3784        } else {
 3785            log::error!("update_selection dispatched with no pending selection");
 3786            return;
 3787        }
 3788
 3789        self.apply_scroll_delta(scroll_delta, window, cx);
 3790        cx.notify();
 3791    }
 3792
 3793    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3794        self.columnar_selection_state.take();
 3795        if let Some(pending_mode) = self.selections.pending_mode() {
 3796            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3797            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3798                s.select(selections);
 3799                s.clear_pending();
 3800                if s.is_extending() {
 3801                    s.set_is_extending(false);
 3802                } else {
 3803                    s.set_select_mode(pending_mode);
 3804                }
 3805            });
 3806        }
 3807    }
 3808
 3809    fn select_columns(
 3810        &mut self,
 3811        head: DisplayPoint,
 3812        goal_column: u32,
 3813        display_map: &DisplaySnapshot,
 3814        window: &mut Window,
 3815        cx: &mut Context<Self>,
 3816    ) {
 3817        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3818            return;
 3819        };
 3820
 3821        let tail = match columnar_state {
 3822            ColumnarSelectionState::FromMouse {
 3823                selection_tail,
 3824                display_point,
 3825            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3826            ColumnarSelectionState::FromSelection { selection_tail } => {
 3827                selection_tail.to_display_point(display_map)
 3828            }
 3829        };
 3830
 3831        let start_row = cmp::min(tail.row(), head.row());
 3832        let end_row = cmp::max(tail.row(), head.row());
 3833        let start_column = cmp::min(tail.column(), goal_column);
 3834        let end_column = cmp::max(tail.column(), goal_column);
 3835        let reversed = start_column < tail.column();
 3836
 3837        let selection_ranges = (start_row.0..=end_row.0)
 3838            .map(DisplayRow)
 3839            .filter_map(|row| {
 3840                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3841                    || start_column <= display_map.line_len(row))
 3842                    && !display_map.is_block_line(row)
 3843                {
 3844                    let start = display_map
 3845                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3846                        .to_point(display_map);
 3847                    let end = display_map
 3848                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3849                        .to_point(display_map);
 3850                    if reversed {
 3851                        Some(end..start)
 3852                    } else {
 3853                        Some(start..end)
 3854                    }
 3855                } else {
 3856                    None
 3857                }
 3858            })
 3859            .collect::<Vec<_>>();
 3860        if selection_ranges.is_empty() {
 3861            return;
 3862        }
 3863
 3864        let ranges = match columnar_state {
 3865            ColumnarSelectionState::FromMouse { .. } => {
 3866                let mut non_empty_ranges = selection_ranges
 3867                    .iter()
 3868                    .filter(|selection_range| selection_range.start != selection_range.end)
 3869                    .peekable();
 3870                if non_empty_ranges.peek().is_some() {
 3871                    non_empty_ranges.cloned().collect()
 3872                } else {
 3873                    selection_ranges
 3874                }
 3875            }
 3876            _ => selection_ranges,
 3877        };
 3878
 3879        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3880            s.select_ranges(ranges);
 3881        });
 3882        cx.notify();
 3883    }
 3884
 3885    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3886        self.selections
 3887            .all_adjusted(snapshot)
 3888            .iter()
 3889            .any(|selection| !selection.is_empty())
 3890    }
 3891
 3892    pub fn has_pending_nonempty_selection(&self) -> bool {
 3893        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3894            Some(Selection { start, end, .. }) => start != end,
 3895            None => false,
 3896        };
 3897
 3898        pending_nonempty_selection
 3899            || (self.columnar_selection_state.is_some()
 3900                && self.selections.disjoint_anchors().len() > 1)
 3901    }
 3902
 3903    pub fn has_pending_selection(&self) -> bool {
 3904        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3905    }
 3906
 3907    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3908        self.selection_mark_mode = false;
 3909        self.selection_drag_state = SelectionDragState::None;
 3910
 3911        if self.clear_expanded_diff_hunks(cx) {
 3912            cx.notify();
 3913            return;
 3914        }
 3915        if self.dismiss_menus_and_popups(true, window, cx) {
 3916            return;
 3917        }
 3918
 3919        if self.mode.is_full()
 3920            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3921        {
 3922            return;
 3923        }
 3924
 3925        cx.propagate();
 3926    }
 3927
 3928    pub fn dismiss_menus_and_popups(
 3929        &mut self,
 3930        is_user_requested: bool,
 3931        window: &mut Window,
 3932        cx: &mut Context<Self>,
 3933    ) -> bool {
 3934        if self.take_rename(false, window, cx).is_some() {
 3935            return true;
 3936        }
 3937
 3938        if self.hide_blame_popover(true, cx) {
 3939            return true;
 3940        }
 3941
 3942        if hide_hover(self, cx) {
 3943            return true;
 3944        }
 3945
 3946        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3947            return true;
 3948        }
 3949
 3950        if self.hide_context_menu(window, cx).is_some() {
 3951            return true;
 3952        }
 3953
 3954        if self.mouse_context_menu.take().is_some() {
 3955            return true;
 3956        }
 3957
 3958        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3959            return true;
 3960        }
 3961
 3962        if self.snippet_stack.pop().is_some() {
 3963            return true;
 3964        }
 3965
 3966        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3967            self.dismiss_diagnostics(cx);
 3968            return true;
 3969        }
 3970
 3971        false
 3972    }
 3973
 3974    fn linked_editing_ranges_for(
 3975        &self,
 3976        selection: Range<text::Anchor>,
 3977        cx: &App,
 3978    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3979        if self.linked_edit_ranges.is_empty() {
 3980            return None;
 3981        }
 3982        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3983            selection.end.buffer_id.and_then(|end_buffer_id| {
 3984                if selection.start.buffer_id != Some(end_buffer_id) {
 3985                    return None;
 3986                }
 3987                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3988                let snapshot = buffer.read(cx).snapshot();
 3989                self.linked_edit_ranges
 3990                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3991                    .map(|ranges| (ranges, snapshot, buffer))
 3992            })?;
 3993        use text::ToOffset as TO;
 3994        // find offset from the start of current range to current cursor position
 3995        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3996
 3997        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3998        let start_difference = start_offset - start_byte_offset;
 3999        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4000        let end_difference = end_offset - start_byte_offset;
 4001        // Current range has associated linked ranges.
 4002        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4003        for range in linked_ranges.iter() {
 4004            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4005            let end_offset = start_offset + end_difference;
 4006            let start_offset = start_offset + start_difference;
 4007            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4008                continue;
 4009            }
 4010            if self.selections.disjoint_anchor_ranges().any(|s| {
 4011                if s.start.buffer_id != selection.start.buffer_id
 4012                    || s.end.buffer_id != selection.end.buffer_id
 4013                {
 4014                    return false;
 4015                }
 4016                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4017                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4018            }) {
 4019                continue;
 4020            }
 4021            let start = buffer_snapshot.anchor_after(start_offset);
 4022            let end = buffer_snapshot.anchor_after(end_offset);
 4023            linked_edits
 4024                .entry(buffer.clone())
 4025                .or_default()
 4026                .push(start..end);
 4027        }
 4028        Some(linked_edits)
 4029    }
 4030
 4031    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4032        let text: Arc<str> = text.into();
 4033
 4034        if self.read_only(cx) {
 4035            return;
 4036        }
 4037
 4038        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4039
 4040        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4041        let mut bracket_inserted = false;
 4042        let mut edits = Vec::new();
 4043        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4044        let mut new_selections = Vec::with_capacity(selections.len());
 4045        let mut new_autoclose_regions = Vec::new();
 4046        let snapshot = self.buffer.read(cx).read(cx);
 4047        let mut clear_linked_edit_ranges = false;
 4048
 4049        for (selection, autoclose_region) in
 4050            self.selections_with_autoclose_regions(selections, &snapshot)
 4051        {
 4052            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4053                // Determine if the inserted text matches the opening or closing
 4054                // bracket of any of this language's bracket pairs.
 4055                let mut bracket_pair = None;
 4056                let mut is_bracket_pair_start = false;
 4057                let mut is_bracket_pair_end = false;
 4058                if !text.is_empty() {
 4059                    let mut bracket_pair_matching_end = None;
 4060                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4061                    //  and they are removing the character that triggered IME popup.
 4062                    for (pair, enabled) in scope.brackets() {
 4063                        if !pair.close && !pair.surround {
 4064                            continue;
 4065                        }
 4066
 4067                        if enabled && pair.start.ends_with(text.as_ref()) {
 4068                            let prefix_len = pair.start.len() - text.len();
 4069                            let preceding_text_matches_prefix = prefix_len == 0
 4070                                || (selection.start.column >= (prefix_len as u32)
 4071                                    && snapshot.contains_str_at(
 4072                                        Point::new(
 4073                                            selection.start.row,
 4074                                            selection.start.column - (prefix_len as u32),
 4075                                        ),
 4076                                        &pair.start[..prefix_len],
 4077                                    ));
 4078                            if preceding_text_matches_prefix {
 4079                                bracket_pair = Some(pair.clone());
 4080                                is_bracket_pair_start = true;
 4081                                break;
 4082                            }
 4083                        }
 4084                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4085                        {
 4086                            // take first bracket pair matching end, but don't break in case a later bracket
 4087                            // pair matches start
 4088                            bracket_pair_matching_end = Some(pair.clone());
 4089                        }
 4090                    }
 4091                    if let Some(end) = bracket_pair_matching_end
 4092                        && bracket_pair.is_none()
 4093                    {
 4094                        bracket_pair = Some(end);
 4095                        is_bracket_pair_end = true;
 4096                    }
 4097                }
 4098
 4099                if let Some(bracket_pair) = bracket_pair {
 4100                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4101                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4102                    let auto_surround =
 4103                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4104                    if selection.is_empty() {
 4105                        if is_bracket_pair_start {
 4106                            // If the inserted text is a suffix of an opening bracket and the
 4107                            // selection is preceded by the rest of the opening bracket, then
 4108                            // insert the closing bracket.
 4109                            let following_text_allows_autoclose = snapshot
 4110                                .chars_at(selection.start)
 4111                                .next()
 4112                                .is_none_or(|c| scope.should_autoclose_before(c));
 4113
 4114                            let preceding_text_allows_autoclose = selection.start.column == 0
 4115                                || snapshot
 4116                                    .reversed_chars_at(selection.start)
 4117                                    .next()
 4118                                    .is_none_or(|c| {
 4119                                        bracket_pair.start != bracket_pair.end
 4120                                            || !snapshot
 4121                                                .char_classifier_at(selection.start)
 4122                                                .is_word(c)
 4123                                    });
 4124
 4125                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4126                                && bracket_pair.start.len() == 1
 4127                            {
 4128                                let target = bracket_pair.start.chars().next().unwrap();
 4129                                let current_line_count = snapshot
 4130                                    .reversed_chars_at(selection.start)
 4131                                    .take_while(|&c| c != '\n')
 4132                                    .filter(|&c| c == target)
 4133                                    .count();
 4134                                current_line_count % 2 == 1
 4135                            } else {
 4136                                false
 4137                            };
 4138
 4139                            if autoclose
 4140                                && bracket_pair.close
 4141                                && following_text_allows_autoclose
 4142                                && preceding_text_allows_autoclose
 4143                                && !is_closing_quote
 4144                            {
 4145                                let anchor = snapshot.anchor_before(selection.end);
 4146                                new_selections.push((selection.map(|_| anchor), text.len()));
 4147                                new_autoclose_regions.push((
 4148                                    anchor,
 4149                                    text.len(),
 4150                                    selection.id,
 4151                                    bracket_pair.clone(),
 4152                                ));
 4153                                edits.push((
 4154                                    selection.range(),
 4155                                    format!("{}{}", text, bracket_pair.end).into(),
 4156                                ));
 4157                                bracket_inserted = true;
 4158                                continue;
 4159                            }
 4160                        }
 4161
 4162                        if let Some(region) = autoclose_region {
 4163                            // If the selection is followed by an auto-inserted closing bracket,
 4164                            // then don't insert that closing bracket again; just move the selection
 4165                            // past the closing bracket.
 4166                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4167                                && text.as_ref() == region.pair.end.as_str()
 4168                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4169                            if should_skip {
 4170                                let anchor = snapshot.anchor_after(selection.end);
 4171                                new_selections
 4172                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4173                                continue;
 4174                            }
 4175                        }
 4176
 4177                        let always_treat_brackets_as_autoclosed = snapshot
 4178                            .language_settings_at(selection.start, cx)
 4179                            .always_treat_brackets_as_autoclosed;
 4180                        if always_treat_brackets_as_autoclosed
 4181                            && is_bracket_pair_end
 4182                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4183                        {
 4184                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4185                            // and the inserted text is a closing bracket and the selection is followed
 4186                            // by the closing bracket then move the selection past the closing bracket.
 4187                            let anchor = snapshot.anchor_after(selection.end);
 4188                            new_selections.push((selection.map(|_| anchor), text.len()));
 4189                            continue;
 4190                        }
 4191                    }
 4192                    // If an opening bracket is 1 character long and is typed while
 4193                    // text is selected, then surround that text with the bracket pair.
 4194                    else if auto_surround
 4195                        && bracket_pair.surround
 4196                        && is_bracket_pair_start
 4197                        && bracket_pair.start.chars().count() == 1
 4198                    {
 4199                        edits.push((selection.start..selection.start, text.clone()));
 4200                        edits.push((
 4201                            selection.end..selection.end,
 4202                            bracket_pair.end.as_str().into(),
 4203                        ));
 4204                        bracket_inserted = true;
 4205                        new_selections.push((
 4206                            Selection {
 4207                                id: selection.id,
 4208                                start: snapshot.anchor_after(selection.start),
 4209                                end: snapshot.anchor_before(selection.end),
 4210                                reversed: selection.reversed,
 4211                                goal: selection.goal,
 4212                            },
 4213                            0,
 4214                        ));
 4215                        continue;
 4216                    }
 4217                }
 4218            }
 4219
 4220            if self.auto_replace_emoji_shortcode
 4221                && selection.is_empty()
 4222                && text.as_ref().ends_with(':')
 4223                && let Some(possible_emoji_short_code) =
 4224                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4225                && !possible_emoji_short_code.is_empty()
 4226                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4227            {
 4228                let emoji_shortcode_start = Point::new(
 4229                    selection.start.row,
 4230                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4231                );
 4232
 4233                // Remove shortcode from buffer
 4234                edits.push((
 4235                    emoji_shortcode_start..selection.start,
 4236                    "".to_string().into(),
 4237                ));
 4238                new_selections.push((
 4239                    Selection {
 4240                        id: selection.id,
 4241                        start: snapshot.anchor_after(emoji_shortcode_start),
 4242                        end: snapshot.anchor_before(selection.start),
 4243                        reversed: selection.reversed,
 4244                        goal: selection.goal,
 4245                    },
 4246                    0,
 4247                ));
 4248
 4249                // Insert emoji
 4250                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4251                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4252                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4253
 4254                continue;
 4255            }
 4256
 4257            // If not handling any auto-close operation, then just replace the selected
 4258            // text with the given input and move the selection to the end of the
 4259            // newly inserted text.
 4260            let anchor = snapshot.anchor_after(selection.end);
 4261            if !self.linked_edit_ranges.is_empty() {
 4262                let start_anchor = snapshot.anchor_before(selection.start);
 4263
 4264                let is_word_char = text.chars().next().is_none_or(|char| {
 4265                    let classifier = snapshot
 4266                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4267                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4268                    classifier.is_word(char)
 4269                });
 4270
 4271                if is_word_char {
 4272                    if let Some(ranges) = self
 4273                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4274                    {
 4275                        for (buffer, edits) in ranges {
 4276                            linked_edits
 4277                                .entry(buffer.clone())
 4278                                .or_default()
 4279                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4280                        }
 4281                    }
 4282                } else {
 4283                    clear_linked_edit_ranges = true;
 4284                }
 4285            }
 4286
 4287            new_selections.push((selection.map(|_| anchor), 0));
 4288            edits.push((selection.start..selection.end, text.clone()));
 4289        }
 4290
 4291        drop(snapshot);
 4292
 4293        self.transact(window, cx, |this, window, cx| {
 4294            if clear_linked_edit_ranges {
 4295                this.linked_edit_ranges.clear();
 4296            }
 4297            let initial_buffer_versions =
 4298                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4299
 4300            this.buffer.update(cx, |buffer, cx| {
 4301                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4302            });
 4303            for (buffer, edits) in linked_edits {
 4304                buffer.update(cx, |buffer, cx| {
 4305                    let snapshot = buffer.snapshot();
 4306                    let edits = edits
 4307                        .into_iter()
 4308                        .map(|(range, text)| {
 4309                            use text::ToPoint as TP;
 4310                            let end_point = TP::to_point(&range.end, &snapshot);
 4311                            let start_point = TP::to_point(&range.start, &snapshot);
 4312                            (start_point..end_point, text)
 4313                        })
 4314                        .sorted_by_key(|(range, _)| range.start);
 4315                    buffer.edit(edits, None, cx);
 4316                })
 4317            }
 4318            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4319            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4320            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4321            let new_selections =
 4322                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4323                    .zip(new_selection_deltas)
 4324                    .map(|(selection, delta)| Selection {
 4325                        id: selection.id,
 4326                        start: selection.start + delta,
 4327                        end: selection.end + delta,
 4328                        reversed: selection.reversed,
 4329                        goal: SelectionGoal::None,
 4330                    })
 4331                    .collect::<Vec<_>>();
 4332
 4333            let mut i = 0;
 4334            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4335                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4336                let start = map.buffer_snapshot().anchor_before(position);
 4337                let end = map.buffer_snapshot().anchor_after(position);
 4338                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4339                    match existing_state
 4340                        .range
 4341                        .start
 4342                        .cmp(&start, map.buffer_snapshot())
 4343                    {
 4344                        Ordering::Less => i += 1,
 4345                        Ordering::Greater => break,
 4346                        Ordering::Equal => {
 4347                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4348                                Ordering::Less => i += 1,
 4349                                Ordering::Equal => break,
 4350                                Ordering::Greater => break,
 4351                            }
 4352                        }
 4353                    }
 4354                }
 4355                this.autoclose_regions.insert(
 4356                    i,
 4357                    AutocloseRegion {
 4358                        selection_id,
 4359                        range: start..end,
 4360                        pair,
 4361                    },
 4362                );
 4363            }
 4364
 4365            let had_active_edit_prediction = this.has_active_edit_prediction();
 4366            this.change_selections(
 4367                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4368                window,
 4369                cx,
 4370                |s| s.select(new_selections),
 4371            );
 4372
 4373            if !bracket_inserted
 4374                && let Some(on_type_format_task) =
 4375                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4376            {
 4377                on_type_format_task.detach_and_log_err(cx);
 4378            }
 4379
 4380            let editor_settings = EditorSettings::get_global(cx);
 4381            if bracket_inserted
 4382                && (editor_settings.auto_signature_help
 4383                    || editor_settings.show_signature_help_after_edits)
 4384            {
 4385                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4386            }
 4387
 4388            let trigger_in_words =
 4389                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4390            if this.hard_wrap.is_some() {
 4391                let latest: Range<Point> = this.selections.newest(&map).range();
 4392                if latest.is_empty()
 4393                    && this
 4394                        .buffer()
 4395                        .read(cx)
 4396                        .snapshot(cx)
 4397                        .line_len(MultiBufferRow(latest.start.row))
 4398                        == latest.start.column
 4399                {
 4400                    this.rewrap_impl(
 4401                        RewrapOptions {
 4402                            override_language_settings: true,
 4403                            preserve_existing_whitespace: true,
 4404                        },
 4405                        cx,
 4406                    )
 4407                }
 4408            }
 4409            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4410            refresh_linked_ranges(this, window, cx);
 4411            this.refresh_edit_prediction(true, false, window, cx);
 4412            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4413        });
 4414    }
 4415
 4416    fn find_possible_emoji_shortcode_at_position(
 4417        snapshot: &MultiBufferSnapshot,
 4418        position: Point,
 4419    ) -> Option<String> {
 4420        let mut chars = Vec::new();
 4421        let mut found_colon = false;
 4422        for char in snapshot.reversed_chars_at(position).take(100) {
 4423            // Found a possible emoji shortcode in the middle of the buffer
 4424            if found_colon {
 4425                if char.is_whitespace() {
 4426                    chars.reverse();
 4427                    return Some(chars.iter().collect());
 4428                }
 4429                // If the previous character is not a whitespace, we are in the middle of a word
 4430                // and we only want to complete the shortcode if the word is made up of other emojis
 4431                let mut containing_word = String::new();
 4432                for ch in snapshot
 4433                    .reversed_chars_at(position)
 4434                    .skip(chars.len() + 1)
 4435                    .take(100)
 4436                {
 4437                    if ch.is_whitespace() {
 4438                        break;
 4439                    }
 4440                    containing_word.push(ch);
 4441                }
 4442                let containing_word = containing_word.chars().rev().collect::<String>();
 4443                if util::word_consists_of_emojis(containing_word.as_str()) {
 4444                    chars.reverse();
 4445                    return Some(chars.iter().collect());
 4446                }
 4447            }
 4448
 4449            if char.is_whitespace() || !char.is_ascii() {
 4450                return None;
 4451            }
 4452            if char == ':' {
 4453                found_colon = true;
 4454            } else {
 4455                chars.push(char);
 4456            }
 4457        }
 4458        // Found a possible emoji shortcode at the beginning of the buffer
 4459        chars.reverse();
 4460        Some(chars.iter().collect())
 4461    }
 4462
 4463    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4464        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4465        self.transact(window, cx, |this, window, cx| {
 4466            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4467                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4468                let multi_buffer = this.buffer.read(cx);
 4469                let buffer = multi_buffer.snapshot(cx);
 4470                selections
 4471                    .iter()
 4472                    .map(|selection| {
 4473                        let start_point = selection.start.to_point(&buffer);
 4474                        let mut existing_indent =
 4475                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4476                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4477                        let start = selection.start;
 4478                        let end = selection.end;
 4479                        let selection_is_empty = start == end;
 4480                        let language_scope = buffer.language_scope_at(start);
 4481                        let (
 4482                            comment_delimiter,
 4483                            doc_delimiter,
 4484                            insert_extra_newline,
 4485                            indent_on_newline,
 4486                            indent_on_extra_newline,
 4487                        ) = if let Some(language) = &language_scope {
 4488                            let mut insert_extra_newline =
 4489                                insert_extra_newline_brackets(&buffer, start..end, language)
 4490                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4491
 4492                            // Comment extension on newline is allowed only for cursor selections
 4493                            let comment_delimiter = maybe!({
 4494                                if !selection_is_empty {
 4495                                    return None;
 4496                                }
 4497
 4498                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4499                                    return None;
 4500                                }
 4501
 4502                                let delimiters = language.line_comment_prefixes();
 4503                                let max_len_of_delimiter =
 4504                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4505                                let (snapshot, range) =
 4506                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4507
 4508                                let num_of_whitespaces = snapshot
 4509                                    .chars_for_range(range.clone())
 4510                                    .take_while(|c| c.is_whitespace())
 4511                                    .count();
 4512                                let comment_candidate = snapshot
 4513                                    .chars_for_range(range.clone())
 4514                                    .skip(num_of_whitespaces)
 4515                                    .take(max_len_of_delimiter)
 4516                                    .collect::<String>();
 4517                                let (delimiter, trimmed_len) = delimiters
 4518                                    .iter()
 4519                                    .filter_map(|delimiter| {
 4520                                        let prefix = delimiter.trim_end();
 4521                                        if comment_candidate.starts_with(prefix) {
 4522                                            Some((delimiter, prefix.len()))
 4523                                        } else {
 4524                                            None
 4525                                        }
 4526                                    })
 4527                                    .max_by_key(|(_, len)| *len)?;
 4528
 4529                                if let Some(BlockCommentConfig {
 4530                                    start: block_start, ..
 4531                                }) = language.block_comment()
 4532                                {
 4533                                    let block_start_trimmed = block_start.trim_end();
 4534                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4535                                        let line_content = snapshot
 4536                                            .chars_for_range(range)
 4537                                            .skip(num_of_whitespaces)
 4538                                            .take(block_start_trimmed.len())
 4539                                            .collect::<String>();
 4540
 4541                                        if line_content.starts_with(block_start_trimmed) {
 4542                                            return None;
 4543                                        }
 4544                                    }
 4545                                }
 4546
 4547                                let cursor_is_placed_after_comment_marker =
 4548                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4549                                if cursor_is_placed_after_comment_marker {
 4550                                    Some(delimiter.clone())
 4551                                } else {
 4552                                    None
 4553                                }
 4554                            });
 4555
 4556                            let mut indent_on_newline = IndentSize::spaces(0);
 4557                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4558
 4559                            let doc_delimiter = maybe!({
 4560                                if !selection_is_empty {
 4561                                    return None;
 4562                                }
 4563
 4564                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4565                                    return None;
 4566                                }
 4567
 4568                                let BlockCommentConfig {
 4569                                    start: start_tag,
 4570                                    end: end_tag,
 4571                                    prefix: delimiter,
 4572                                    tab_size: len,
 4573                                } = language.documentation_comment()?;
 4574                                let is_within_block_comment = buffer
 4575                                    .language_scope_at(start_point)
 4576                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4577                                if !is_within_block_comment {
 4578                                    return None;
 4579                                }
 4580
 4581                                let (snapshot, range) =
 4582                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4583
 4584                                let num_of_whitespaces = snapshot
 4585                                    .chars_for_range(range.clone())
 4586                                    .take_while(|c| c.is_whitespace())
 4587                                    .count();
 4588
 4589                                // 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.
 4590                                let column = start_point.column;
 4591                                let cursor_is_after_start_tag = {
 4592                                    let start_tag_len = start_tag.len();
 4593                                    let start_tag_line = snapshot
 4594                                        .chars_for_range(range.clone())
 4595                                        .skip(num_of_whitespaces)
 4596                                        .take(start_tag_len)
 4597                                        .collect::<String>();
 4598                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4599                                        num_of_whitespaces + start_tag_len <= column as usize
 4600                                    } else {
 4601                                        false
 4602                                    }
 4603                                };
 4604
 4605                                let cursor_is_after_delimiter = {
 4606                                    let delimiter_trim = delimiter.trim_end();
 4607                                    let delimiter_line = snapshot
 4608                                        .chars_for_range(range.clone())
 4609                                        .skip(num_of_whitespaces)
 4610                                        .take(delimiter_trim.len())
 4611                                        .collect::<String>();
 4612                                    if delimiter_line.starts_with(delimiter_trim) {
 4613                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4614                                    } else {
 4615                                        false
 4616                                    }
 4617                                };
 4618
 4619                                let cursor_is_before_end_tag_if_exists = {
 4620                                    let mut char_position = 0u32;
 4621                                    let mut end_tag_offset = None;
 4622
 4623                                    'outer: for chunk in snapshot.text_for_range(range) {
 4624                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4625                                            let chars_before_match =
 4626                                                chunk[..byte_pos].chars().count() as u32;
 4627                                            end_tag_offset =
 4628                                                Some(char_position + chars_before_match);
 4629                                            break 'outer;
 4630                                        }
 4631                                        char_position += chunk.chars().count() as u32;
 4632                                    }
 4633
 4634                                    if let Some(end_tag_offset) = end_tag_offset {
 4635                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4636                                        if cursor_is_after_start_tag {
 4637                                            if cursor_is_before_end_tag {
 4638                                                insert_extra_newline = true;
 4639                                            }
 4640                                            let cursor_is_at_start_of_end_tag =
 4641                                                column == end_tag_offset;
 4642                                            if cursor_is_at_start_of_end_tag {
 4643                                                indent_on_extra_newline.len = *len;
 4644                                            }
 4645                                        }
 4646                                        cursor_is_before_end_tag
 4647                                    } else {
 4648                                        true
 4649                                    }
 4650                                };
 4651
 4652                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4653                                    && cursor_is_before_end_tag_if_exists
 4654                                {
 4655                                    if cursor_is_after_start_tag {
 4656                                        indent_on_newline.len = *len;
 4657                                    }
 4658                                    Some(delimiter.clone())
 4659                                } else {
 4660                                    None
 4661                                }
 4662                            });
 4663
 4664                            (
 4665                                comment_delimiter,
 4666                                doc_delimiter,
 4667                                insert_extra_newline,
 4668                                indent_on_newline,
 4669                                indent_on_extra_newline,
 4670                            )
 4671                        } else {
 4672                            (
 4673                                None,
 4674                                None,
 4675                                false,
 4676                                IndentSize::default(),
 4677                                IndentSize::default(),
 4678                            )
 4679                        };
 4680
 4681                        let prevent_auto_indent = doc_delimiter.is_some();
 4682                        let delimiter = comment_delimiter.or(doc_delimiter);
 4683
 4684                        let capacity_for_delimiter =
 4685                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4686                        let mut new_text = String::with_capacity(
 4687                            1 + capacity_for_delimiter
 4688                                + existing_indent.len as usize
 4689                                + indent_on_newline.len as usize
 4690                                + indent_on_extra_newline.len as usize,
 4691                        );
 4692                        new_text.push('\n');
 4693                        new_text.extend(existing_indent.chars());
 4694                        new_text.extend(indent_on_newline.chars());
 4695
 4696                        if let Some(delimiter) = &delimiter {
 4697                            new_text.push_str(delimiter);
 4698                        }
 4699
 4700                        if insert_extra_newline {
 4701                            new_text.push('\n');
 4702                            new_text.extend(existing_indent.chars());
 4703                            new_text.extend(indent_on_extra_newline.chars());
 4704                        }
 4705
 4706                        let anchor = buffer.anchor_after(end);
 4707                        let new_selection = selection.map(|_| anchor);
 4708                        (
 4709                            ((start..end, new_text), prevent_auto_indent),
 4710                            (insert_extra_newline, new_selection),
 4711                        )
 4712                    })
 4713                    .unzip()
 4714            };
 4715
 4716            let mut auto_indent_edits = Vec::new();
 4717            let mut edits = Vec::new();
 4718            for (edit, prevent_auto_indent) in edits_with_flags {
 4719                if prevent_auto_indent {
 4720                    edits.push(edit);
 4721                } else {
 4722                    auto_indent_edits.push(edit);
 4723                }
 4724            }
 4725            if !edits.is_empty() {
 4726                this.edit(edits, cx);
 4727            }
 4728            if !auto_indent_edits.is_empty() {
 4729                this.edit_with_autoindent(auto_indent_edits, cx);
 4730            }
 4731
 4732            let buffer = this.buffer.read(cx).snapshot(cx);
 4733            let new_selections = selection_info
 4734                .into_iter()
 4735                .map(|(extra_newline_inserted, new_selection)| {
 4736                    let mut cursor = new_selection.end.to_point(&buffer);
 4737                    if extra_newline_inserted {
 4738                        cursor.row -= 1;
 4739                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4740                    }
 4741                    new_selection.map(|_| cursor)
 4742                })
 4743                .collect();
 4744
 4745            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4746            this.refresh_edit_prediction(true, false, window, cx);
 4747        });
 4748    }
 4749
 4750    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4751        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4752
 4753        let buffer = self.buffer.read(cx);
 4754        let snapshot = buffer.snapshot(cx);
 4755
 4756        let mut edits = Vec::new();
 4757        let mut rows = Vec::new();
 4758
 4759        for (rows_inserted, selection) in self
 4760            .selections
 4761            .all_adjusted(&self.display_snapshot(cx))
 4762            .into_iter()
 4763            .enumerate()
 4764        {
 4765            let cursor = selection.head();
 4766            let row = cursor.row;
 4767
 4768            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4769
 4770            let newline = "\n".to_string();
 4771            edits.push((start_of_line..start_of_line, newline));
 4772
 4773            rows.push(row + rows_inserted as u32);
 4774        }
 4775
 4776        self.transact(window, cx, |editor, window, cx| {
 4777            editor.edit(edits, cx);
 4778
 4779            editor.change_selections(Default::default(), window, cx, |s| {
 4780                let mut index = 0;
 4781                s.move_cursors_with(|map, _, _| {
 4782                    let row = rows[index];
 4783                    index += 1;
 4784
 4785                    let point = Point::new(row, 0);
 4786                    let boundary = map.next_line_boundary(point).1;
 4787                    let clipped = map.clip_point(boundary, Bias::Left);
 4788
 4789                    (clipped, SelectionGoal::None)
 4790                });
 4791            });
 4792
 4793            let mut indent_edits = Vec::new();
 4794            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4795            for row in rows {
 4796                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4797                for (row, indent) in indents {
 4798                    if indent.len == 0 {
 4799                        continue;
 4800                    }
 4801
 4802                    let text = match indent.kind {
 4803                        IndentKind::Space => " ".repeat(indent.len as usize),
 4804                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4805                    };
 4806                    let point = Point::new(row.0, 0);
 4807                    indent_edits.push((point..point, text));
 4808                }
 4809            }
 4810            editor.edit(indent_edits, cx);
 4811        });
 4812    }
 4813
 4814    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4816
 4817        let buffer = self.buffer.read(cx);
 4818        let snapshot = buffer.snapshot(cx);
 4819
 4820        let mut edits = Vec::new();
 4821        let mut rows = Vec::new();
 4822        let mut rows_inserted = 0;
 4823
 4824        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4825            let cursor = selection.head();
 4826            let row = cursor.row;
 4827
 4828            let point = Point::new(row + 1, 0);
 4829            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4830
 4831            let newline = "\n".to_string();
 4832            edits.push((start_of_line..start_of_line, newline));
 4833
 4834            rows_inserted += 1;
 4835            rows.push(row + rows_inserted);
 4836        }
 4837
 4838        self.transact(window, cx, |editor, window, cx| {
 4839            editor.edit(edits, cx);
 4840
 4841            editor.change_selections(Default::default(), window, cx, |s| {
 4842                let mut index = 0;
 4843                s.move_cursors_with(|map, _, _| {
 4844                    let row = rows[index];
 4845                    index += 1;
 4846
 4847                    let point = Point::new(row, 0);
 4848                    let boundary = map.next_line_boundary(point).1;
 4849                    let clipped = map.clip_point(boundary, Bias::Left);
 4850
 4851                    (clipped, SelectionGoal::None)
 4852                });
 4853            });
 4854
 4855            let mut indent_edits = Vec::new();
 4856            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4857            for row in rows {
 4858                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4859                for (row, indent) in indents {
 4860                    if indent.len == 0 {
 4861                        continue;
 4862                    }
 4863
 4864                    let text = match indent.kind {
 4865                        IndentKind::Space => " ".repeat(indent.len as usize),
 4866                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4867                    };
 4868                    let point = Point::new(row.0, 0);
 4869                    indent_edits.push((point..point, text));
 4870                }
 4871            }
 4872            editor.edit(indent_edits, cx);
 4873        });
 4874    }
 4875
 4876    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4877        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4878            original_indent_columns: Vec::new(),
 4879        });
 4880        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4881    }
 4882
 4883    fn insert_with_autoindent_mode(
 4884        &mut self,
 4885        text: &str,
 4886        autoindent_mode: Option<AutoindentMode>,
 4887        window: &mut Window,
 4888        cx: &mut Context<Self>,
 4889    ) {
 4890        if self.read_only(cx) {
 4891            return;
 4892        }
 4893
 4894        let text: Arc<str> = text.into();
 4895        self.transact(window, cx, |this, window, cx| {
 4896            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4897            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4898                let anchors = {
 4899                    let snapshot = buffer.read(cx);
 4900                    old_selections
 4901                        .iter()
 4902                        .map(|s| {
 4903                            let anchor = snapshot.anchor_after(s.head());
 4904                            s.map(|_| anchor)
 4905                        })
 4906                        .collect::<Vec<_>>()
 4907                };
 4908                buffer.edit(
 4909                    old_selections
 4910                        .iter()
 4911                        .map(|s| (s.start..s.end, text.clone())),
 4912                    autoindent_mode,
 4913                    cx,
 4914                );
 4915                anchors
 4916            });
 4917
 4918            this.change_selections(Default::default(), window, cx, |s| {
 4919                s.select_anchors(selection_anchors);
 4920            });
 4921
 4922            cx.notify();
 4923        });
 4924    }
 4925
 4926    fn trigger_completion_on_input(
 4927        &mut self,
 4928        text: &str,
 4929        trigger_in_words: bool,
 4930        window: &mut Window,
 4931        cx: &mut Context<Self>,
 4932    ) {
 4933        let completions_source = self
 4934            .context_menu
 4935            .borrow()
 4936            .as_ref()
 4937            .and_then(|menu| match menu {
 4938                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4939                CodeContextMenu::CodeActions(_) => None,
 4940            });
 4941
 4942        match completions_source {
 4943            Some(CompletionsMenuSource::Words { .. }) => {
 4944                self.open_or_update_completions_menu(
 4945                    Some(CompletionsMenuSource::Words {
 4946                        ignore_threshold: false,
 4947                    }),
 4948                    None,
 4949                    window,
 4950                    cx,
 4951                );
 4952            }
 4953            Some(CompletionsMenuSource::Normal)
 4954            | Some(CompletionsMenuSource::SnippetChoices)
 4955            | None
 4956                if self.is_completion_trigger(
 4957                    text,
 4958                    trigger_in_words,
 4959                    completions_source.is_some(),
 4960                    cx,
 4961                ) =>
 4962            {
 4963                self.show_completions(
 4964                    &ShowCompletions {
 4965                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4966                    },
 4967                    window,
 4968                    cx,
 4969                )
 4970            }
 4971            _ => {
 4972                self.hide_context_menu(window, cx);
 4973            }
 4974        }
 4975    }
 4976
 4977    fn is_completion_trigger(
 4978        &self,
 4979        text: &str,
 4980        trigger_in_words: bool,
 4981        menu_is_open: bool,
 4982        cx: &mut Context<Self>,
 4983    ) -> bool {
 4984        let position = self.selections.newest_anchor().head();
 4985        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4986            return false;
 4987        };
 4988
 4989        if let Some(completion_provider) = &self.completion_provider {
 4990            completion_provider.is_completion_trigger(
 4991                &buffer,
 4992                position.text_anchor,
 4993                text,
 4994                trigger_in_words,
 4995                menu_is_open,
 4996                cx,
 4997            )
 4998        } else {
 4999            false
 5000        }
 5001    }
 5002
 5003    /// If any empty selections is touching the start of its innermost containing autoclose
 5004    /// region, expand it to select the brackets.
 5005    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5006        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5007        let buffer = self.buffer.read(cx).read(cx);
 5008        let new_selections = self
 5009            .selections_with_autoclose_regions(selections, &buffer)
 5010            .map(|(mut selection, region)| {
 5011                if !selection.is_empty() {
 5012                    return selection;
 5013                }
 5014
 5015                if let Some(region) = region {
 5016                    let mut range = region.range.to_offset(&buffer);
 5017                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5018                        range.start -= region.pair.start.len();
 5019                        if buffer.contains_str_at(range.start, &region.pair.start)
 5020                            && buffer.contains_str_at(range.end, &region.pair.end)
 5021                        {
 5022                            range.end += region.pair.end.len();
 5023                            selection.start = range.start;
 5024                            selection.end = range.end;
 5025
 5026                            return selection;
 5027                        }
 5028                    }
 5029                }
 5030
 5031                let always_treat_brackets_as_autoclosed = buffer
 5032                    .language_settings_at(selection.start, cx)
 5033                    .always_treat_brackets_as_autoclosed;
 5034
 5035                if !always_treat_brackets_as_autoclosed {
 5036                    return selection;
 5037                }
 5038
 5039                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5040                    for (pair, enabled) in scope.brackets() {
 5041                        if !enabled || !pair.close {
 5042                            continue;
 5043                        }
 5044
 5045                        if buffer.contains_str_at(selection.start, &pair.end) {
 5046                            let pair_start_len = pair.start.len();
 5047                            if buffer.contains_str_at(
 5048                                selection.start.saturating_sub(pair_start_len),
 5049                                &pair.start,
 5050                            ) {
 5051                                selection.start -= pair_start_len;
 5052                                selection.end += pair.end.len();
 5053
 5054                                return selection;
 5055                            }
 5056                        }
 5057                    }
 5058                }
 5059
 5060                selection
 5061            })
 5062            .collect();
 5063
 5064        drop(buffer);
 5065        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5066            selections.select(new_selections)
 5067        });
 5068    }
 5069
 5070    /// Iterate the given selections, and for each one, find the smallest surrounding
 5071    /// autoclose region. This uses the ordering of the selections and the autoclose
 5072    /// regions to avoid repeated comparisons.
 5073    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5074        &'a self,
 5075        selections: impl IntoIterator<Item = Selection<D>>,
 5076        buffer: &'a MultiBufferSnapshot,
 5077    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5078        let mut i = 0;
 5079        let mut regions = self.autoclose_regions.as_slice();
 5080        selections.into_iter().map(move |selection| {
 5081            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5082
 5083            let mut enclosing = None;
 5084            while let Some(pair_state) = regions.get(i) {
 5085                if pair_state.range.end.to_offset(buffer) < range.start {
 5086                    regions = &regions[i + 1..];
 5087                    i = 0;
 5088                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5089                    break;
 5090                } else {
 5091                    if pair_state.selection_id == selection.id {
 5092                        enclosing = Some(pair_state);
 5093                    }
 5094                    i += 1;
 5095                }
 5096            }
 5097
 5098            (selection, enclosing)
 5099        })
 5100    }
 5101
 5102    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5103    fn invalidate_autoclose_regions(
 5104        &mut self,
 5105        mut selections: &[Selection<Anchor>],
 5106        buffer: &MultiBufferSnapshot,
 5107    ) {
 5108        self.autoclose_regions.retain(|state| {
 5109            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5110                return false;
 5111            }
 5112
 5113            let mut i = 0;
 5114            while let Some(selection) = selections.get(i) {
 5115                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5116                    selections = &selections[1..];
 5117                    continue;
 5118                }
 5119                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5120                    break;
 5121                }
 5122                if selection.id == state.selection_id {
 5123                    return true;
 5124                } else {
 5125                    i += 1;
 5126                }
 5127            }
 5128            false
 5129        });
 5130    }
 5131
 5132    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5133        let offset = position.to_offset(buffer);
 5134        let (word_range, kind) =
 5135            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5136        if offset > word_range.start && kind == Some(CharKind::Word) {
 5137            Some(
 5138                buffer
 5139                    .text_for_range(word_range.start..offset)
 5140                    .collect::<String>(),
 5141            )
 5142        } else {
 5143            None
 5144        }
 5145    }
 5146
 5147    pub fn visible_excerpts(
 5148        &self,
 5149        cx: &mut Context<Editor>,
 5150    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5151        let Some(project) = self.project() else {
 5152            return HashMap::default();
 5153        };
 5154        let project = project.read(cx);
 5155        let multi_buffer = self.buffer().read(cx);
 5156        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5157        let multi_buffer_visible_start = self
 5158            .scroll_manager
 5159            .anchor()
 5160            .anchor
 5161            .to_point(&multi_buffer_snapshot);
 5162        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5163            multi_buffer_visible_start
 5164                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5165            Bias::Left,
 5166        );
 5167        multi_buffer_snapshot
 5168            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5169            .into_iter()
 5170            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5171            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5172                let buffer_file = project::File::from_dyn(buffer.file())?;
 5173                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5174                let worktree_entry = buffer_worktree
 5175                    .read(cx)
 5176                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5177                if worktree_entry.is_ignored {
 5178                    None
 5179                } else {
 5180                    Some((
 5181                        excerpt_id,
 5182                        (
 5183                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5184                            buffer.version().clone(),
 5185                            excerpt_visible_range,
 5186                        ),
 5187                    ))
 5188                }
 5189            })
 5190            .collect()
 5191    }
 5192
 5193    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5194        TextLayoutDetails {
 5195            text_system: window.text_system().clone(),
 5196            editor_style: self.style.clone().unwrap(),
 5197            rem_size: window.rem_size(),
 5198            scroll_anchor: self.scroll_manager.anchor(),
 5199            visible_rows: self.visible_line_count(),
 5200            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5201        }
 5202    }
 5203
 5204    fn trigger_on_type_formatting(
 5205        &self,
 5206        input: String,
 5207        window: &mut Window,
 5208        cx: &mut Context<Self>,
 5209    ) -> Option<Task<Result<()>>> {
 5210        if input.len() != 1 {
 5211            return None;
 5212        }
 5213
 5214        let project = self.project()?;
 5215        let position = self.selections.newest_anchor().head();
 5216        let (buffer, buffer_position) = self
 5217            .buffer
 5218            .read(cx)
 5219            .text_anchor_for_position(position, cx)?;
 5220
 5221        let settings = language_settings::language_settings(
 5222            buffer
 5223                .read(cx)
 5224                .language_at(buffer_position)
 5225                .map(|l| l.name()),
 5226            buffer.read(cx).file(),
 5227            cx,
 5228        );
 5229        if !settings.use_on_type_format {
 5230            return None;
 5231        }
 5232
 5233        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5234        // hence we do LSP request & edit on host side only — add formats to host's history.
 5235        let push_to_lsp_host_history = true;
 5236        // If this is not the host, append its history with new edits.
 5237        let push_to_client_history = project.read(cx).is_via_collab();
 5238
 5239        let on_type_formatting = project.update(cx, |project, cx| {
 5240            project.on_type_format(
 5241                buffer.clone(),
 5242                buffer_position,
 5243                input,
 5244                push_to_lsp_host_history,
 5245                cx,
 5246            )
 5247        });
 5248        Some(cx.spawn_in(window, async move |editor, cx| {
 5249            if let Some(transaction) = on_type_formatting.await? {
 5250                if push_to_client_history {
 5251                    buffer
 5252                        .update(cx, |buffer, _| {
 5253                            buffer.push_transaction(transaction, Instant::now());
 5254                            buffer.finalize_last_transaction();
 5255                        })
 5256                        .ok();
 5257                }
 5258                editor.update(cx, |editor, cx| {
 5259                    editor.refresh_document_highlights(cx);
 5260                })?;
 5261            }
 5262            Ok(())
 5263        }))
 5264    }
 5265
 5266    pub fn show_word_completions(
 5267        &mut self,
 5268        _: &ShowWordCompletions,
 5269        window: &mut Window,
 5270        cx: &mut Context<Self>,
 5271    ) {
 5272        self.open_or_update_completions_menu(
 5273            Some(CompletionsMenuSource::Words {
 5274                ignore_threshold: true,
 5275            }),
 5276            None,
 5277            window,
 5278            cx,
 5279        );
 5280    }
 5281
 5282    pub fn show_completions(
 5283        &mut self,
 5284        options: &ShowCompletions,
 5285        window: &mut Window,
 5286        cx: &mut Context<Self>,
 5287    ) {
 5288        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5289    }
 5290
 5291    fn open_or_update_completions_menu(
 5292        &mut self,
 5293        requested_source: Option<CompletionsMenuSource>,
 5294        trigger: Option<&str>,
 5295        window: &mut Window,
 5296        cx: &mut Context<Self>,
 5297    ) {
 5298        if self.pending_rename.is_some() {
 5299            return;
 5300        }
 5301
 5302        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5303
 5304        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5305        // inserted and selected. To handle that case, the start of the selection is used so that
 5306        // the menu starts with all choices.
 5307        let position = self
 5308            .selections
 5309            .newest_anchor()
 5310            .start
 5311            .bias_right(&multibuffer_snapshot);
 5312        if position.diff_base_anchor.is_some() {
 5313            return;
 5314        }
 5315        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5316        let Some(buffer) = buffer_position
 5317            .buffer_id
 5318            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5319        else {
 5320            return;
 5321        };
 5322        let buffer_snapshot = buffer.read(cx).snapshot();
 5323
 5324        let query: Option<Arc<String>> =
 5325            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5326                .map(|query| query.into());
 5327
 5328        drop(multibuffer_snapshot);
 5329
 5330        // Hide the current completions menu when query is empty. Without this, cached
 5331        // completions from before the trigger char may be reused (#32774).
 5332        if query.is_none() {
 5333            let menu_is_open = matches!(
 5334                self.context_menu.borrow().as_ref(),
 5335                Some(CodeContextMenu::Completions(_))
 5336            );
 5337            if menu_is_open {
 5338                self.hide_context_menu(window, cx);
 5339            }
 5340        }
 5341
 5342        let mut ignore_word_threshold = false;
 5343        let provider = match requested_source {
 5344            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5345            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5346                ignore_word_threshold = ignore_threshold;
 5347                None
 5348            }
 5349            Some(CompletionsMenuSource::SnippetChoices) => {
 5350                log::error!("bug: SnippetChoices requested_source is not handled");
 5351                None
 5352            }
 5353        };
 5354
 5355        let sort_completions = provider
 5356            .as_ref()
 5357            .is_some_and(|provider| provider.sort_completions());
 5358
 5359        let filter_completions = provider
 5360            .as_ref()
 5361            .is_none_or(|provider| provider.filter_completions());
 5362
 5363        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5364            if filter_completions {
 5365                menu.filter(query.clone(), provider.clone(), window, cx);
 5366            }
 5367            // When `is_incomplete` is false, no need to re-query completions when the current query
 5368            // is a suffix of the initial query.
 5369            if !menu.is_incomplete {
 5370                // If the new query is a suffix of the old query (typing more characters) and
 5371                // the previous result was complete, the existing completions can be filtered.
 5372                //
 5373                // Note that this is always true for snippet completions.
 5374                let query_matches = match (&menu.initial_query, &query) {
 5375                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5376                    (None, _) => true,
 5377                    _ => false,
 5378                };
 5379                if query_matches {
 5380                    let position_matches = if menu.initial_position == position {
 5381                        true
 5382                    } else {
 5383                        let snapshot = self.buffer.read(cx).read(cx);
 5384                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5385                    };
 5386                    if position_matches {
 5387                        return;
 5388                    }
 5389                }
 5390            }
 5391        };
 5392
 5393        let trigger_kind = match trigger {
 5394            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5395                CompletionTriggerKind::TRIGGER_CHARACTER
 5396            }
 5397            _ => CompletionTriggerKind::INVOKED,
 5398        };
 5399        let completion_context = CompletionContext {
 5400            trigger_character: trigger.and_then(|trigger| {
 5401                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5402                    Some(String::from(trigger))
 5403                } else {
 5404                    None
 5405                }
 5406            }),
 5407            trigger_kind,
 5408        };
 5409
 5410        let Anchor {
 5411            excerpt_id: buffer_excerpt_id,
 5412            text_anchor: buffer_position,
 5413            ..
 5414        } = buffer_position;
 5415
 5416        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5417            buffer_snapshot.surrounding_word(buffer_position, None)
 5418        {
 5419            let word_to_exclude = buffer_snapshot
 5420                .text_for_range(word_range.clone())
 5421                .collect::<String>();
 5422            (
 5423                buffer_snapshot.anchor_before(word_range.start)
 5424                    ..buffer_snapshot.anchor_after(buffer_position),
 5425                Some(word_to_exclude),
 5426            )
 5427        } else {
 5428            (buffer_position..buffer_position, None)
 5429        };
 5430
 5431        let language = buffer_snapshot
 5432            .language_at(buffer_position)
 5433            .map(|language| language.name());
 5434
 5435        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5436            .completions
 5437            .clone();
 5438
 5439        let show_completion_documentation = buffer_snapshot
 5440            .settings_at(buffer_position, cx)
 5441            .show_completion_documentation;
 5442
 5443        // The document can be large, so stay in reasonable bounds when searching for words,
 5444        // otherwise completion pop-up might be slow to appear.
 5445        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5446        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5447        let min_word_search = buffer_snapshot.clip_point(
 5448            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5449            Bias::Left,
 5450        );
 5451        let max_word_search = buffer_snapshot.clip_point(
 5452            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5453            Bias::Right,
 5454        );
 5455        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5456            ..buffer_snapshot.point_to_offset(max_word_search);
 5457
 5458        let skip_digits = query
 5459            .as_ref()
 5460            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5461
 5462        let omit_word_completions = !self.word_completions_enabled
 5463            || (!ignore_word_threshold
 5464                && match &query {
 5465                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5466                    None => completion_settings.words_min_length != 0,
 5467                });
 5468
 5469        let (mut words, provider_responses) = match &provider {
 5470            Some(provider) => {
 5471                let provider_responses = provider.completions(
 5472                    buffer_excerpt_id,
 5473                    &buffer,
 5474                    buffer_position,
 5475                    completion_context,
 5476                    window,
 5477                    cx,
 5478                );
 5479
 5480                let words = match (omit_word_completions, completion_settings.words) {
 5481                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5482                        Task::ready(BTreeMap::default())
 5483                    }
 5484                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5485                        .background_spawn(async move {
 5486                            buffer_snapshot.words_in_range(WordsQuery {
 5487                                fuzzy_contents: None,
 5488                                range: word_search_range,
 5489                                skip_digits,
 5490                            })
 5491                        }),
 5492                };
 5493
 5494                (words, provider_responses)
 5495            }
 5496            None => {
 5497                let words = if omit_word_completions {
 5498                    Task::ready(BTreeMap::default())
 5499                } else {
 5500                    cx.background_spawn(async move {
 5501                        buffer_snapshot.words_in_range(WordsQuery {
 5502                            fuzzy_contents: None,
 5503                            range: word_search_range,
 5504                            skip_digits,
 5505                        })
 5506                    })
 5507                };
 5508                (words, Task::ready(Ok(Vec::new())))
 5509            }
 5510        };
 5511
 5512        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5513
 5514        let id = post_inc(&mut self.next_completion_id);
 5515        let task = cx.spawn_in(window, async move |editor, cx| {
 5516            let Ok(()) = editor.update(cx, |this, _| {
 5517                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5518            }) else {
 5519                return;
 5520            };
 5521
 5522            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5523            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5524            let mut completions = Vec::new();
 5525            let mut is_incomplete = false;
 5526            let mut display_options: Option<CompletionDisplayOptions> = None;
 5527            if let Some(provider_responses) = provider_responses.await.log_err()
 5528                && !provider_responses.is_empty()
 5529            {
 5530                for response in provider_responses {
 5531                    completions.extend(response.completions);
 5532                    is_incomplete = is_incomplete || response.is_incomplete;
 5533                    match display_options.as_mut() {
 5534                        None => {
 5535                            display_options = Some(response.display_options);
 5536                        }
 5537                        Some(options) => options.merge(&response.display_options),
 5538                    }
 5539                }
 5540                if completion_settings.words == WordsCompletionMode::Fallback {
 5541                    words = Task::ready(BTreeMap::default());
 5542                }
 5543            }
 5544            let display_options = display_options.unwrap_or_default();
 5545
 5546            let mut words = words.await;
 5547            if let Some(word_to_exclude) = &word_to_exclude {
 5548                words.remove(word_to_exclude);
 5549            }
 5550            for lsp_completion in &completions {
 5551                words.remove(&lsp_completion.new_text);
 5552            }
 5553            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5554                replace_range: word_replace_range.clone(),
 5555                new_text: word.clone(),
 5556                label: CodeLabel::plain(word, None),
 5557                icon_path: None,
 5558                documentation: None,
 5559                source: CompletionSource::BufferWord {
 5560                    word_range,
 5561                    resolved: false,
 5562                },
 5563                insert_text_mode: Some(InsertTextMode::AS_IS),
 5564                confirm: None,
 5565            }));
 5566
 5567            let menu = if completions.is_empty() {
 5568                None
 5569            } else {
 5570                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5571                    let languages = editor
 5572                        .workspace
 5573                        .as_ref()
 5574                        .and_then(|(workspace, _)| workspace.upgrade())
 5575                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5576                    let menu = CompletionsMenu::new(
 5577                        id,
 5578                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5579                        sort_completions,
 5580                        show_completion_documentation,
 5581                        position,
 5582                        query.clone(),
 5583                        is_incomplete,
 5584                        buffer.clone(),
 5585                        completions.into(),
 5586                        display_options,
 5587                        snippet_sort_order,
 5588                        languages,
 5589                        language,
 5590                        cx,
 5591                    );
 5592
 5593                    let query = if filter_completions { query } else { None };
 5594                    let matches_task = if let Some(query) = query {
 5595                        menu.do_async_filtering(query, cx)
 5596                    } else {
 5597                        Task::ready(menu.unfiltered_matches())
 5598                    };
 5599                    (menu, matches_task)
 5600                }) else {
 5601                    return;
 5602                };
 5603
 5604                let matches = matches_task.await;
 5605
 5606                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5607                    // Newer menu already set, so exit.
 5608                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5609                        editor.context_menu.borrow().as_ref()
 5610                        && prev_menu.id > id
 5611                    {
 5612                        return;
 5613                    };
 5614
 5615                    // Only valid to take prev_menu because it the new menu is immediately set
 5616                    // below, or the menu is hidden.
 5617                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5618                        editor.context_menu.borrow_mut().take()
 5619                    {
 5620                        let position_matches =
 5621                            if prev_menu.initial_position == menu.initial_position {
 5622                                true
 5623                            } else {
 5624                                let snapshot = editor.buffer.read(cx).read(cx);
 5625                                prev_menu.initial_position.to_offset(&snapshot)
 5626                                    == menu.initial_position.to_offset(&snapshot)
 5627                            };
 5628                        if position_matches {
 5629                            // Preserve markdown cache before `set_filter_results` because it will
 5630                            // try to populate the documentation cache.
 5631                            menu.preserve_markdown_cache(prev_menu);
 5632                        }
 5633                    };
 5634
 5635                    menu.set_filter_results(matches, provider, window, cx);
 5636                }) else {
 5637                    return;
 5638                };
 5639
 5640                menu.visible().then_some(menu)
 5641            };
 5642
 5643            editor
 5644                .update_in(cx, |editor, window, cx| {
 5645                    if editor.focus_handle.is_focused(window)
 5646                        && let Some(menu) = menu
 5647                    {
 5648                        *editor.context_menu.borrow_mut() =
 5649                            Some(CodeContextMenu::Completions(menu));
 5650
 5651                        crate::hover_popover::hide_hover(editor, cx);
 5652                        if editor.show_edit_predictions_in_menu() {
 5653                            editor.update_visible_edit_prediction(window, cx);
 5654                        } else {
 5655                            editor.discard_edit_prediction(false, cx);
 5656                        }
 5657
 5658                        cx.notify();
 5659                        return;
 5660                    }
 5661
 5662                    if editor.completion_tasks.len() <= 1 {
 5663                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5664                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5665                        // If it was already hidden and we don't show edit predictions in the menu,
 5666                        // we should also show the edit prediction when available.
 5667                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5668                            editor.update_visible_edit_prediction(window, cx);
 5669                        }
 5670                    }
 5671                })
 5672                .ok();
 5673        });
 5674
 5675        self.completion_tasks.push((id, task));
 5676    }
 5677
 5678    #[cfg(feature = "test-support")]
 5679    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5680        let menu = self.context_menu.borrow();
 5681        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5682            let completions = menu.completions.borrow();
 5683            Some(completions.to_vec())
 5684        } else {
 5685            None
 5686        }
 5687    }
 5688
 5689    pub fn with_completions_menu_matching_id<R>(
 5690        &self,
 5691        id: CompletionId,
 5692        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5693    ) -> R {
 5694        let mut context_menu = self.context_menu.borrow_mut();
 5695        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5696            return f(None);
 5697        };
 5698        if completions_menu.id != id {
 5699            return f(None);
 5700        }
 5701        f(Some(completions_menu))
 5702    }
 5703
 5704    pub fn confirm_completion(
 5705        &mut self,
 5706        action: &ConfirmCompletion,
 5707        window: &mut Window,
 5708        cx: &mut Context<Self>,
 5709    ) -> Option<Task<Result<()>>> {
 5710        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5711        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5712    }
 5713
 5714    pub fn confirm_completion_insert(
 5715        &mut self,
 5716        _: &ConfirmCompletionInsert,
 5717        window: &mut Window,
 5718        cx: &mut Context<Self>,
 5719    ) -> Option<Task<Result<()>>> {
 5720        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5721        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5722    }
 5723
 5724    pub fn confirm_completion_replace(
 5725        &mut self,
 5726        _: &ConfirmCompletionReplace,
 5727        window: &mut Window,
 5728        cx: &mut Context<Self>,
 5729    ) -> Option<Task<Result<()>>> {
 5730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5731        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5732    }
 5733
 5734    pub fn compose_completion(
 5735        &mut self,
 5736        action: &ComposeCompletion,
 5737        window: &mut Window,
 5738        cx: &mut Context<Self>,
 5739    ) -> Option<Task<Result<()>>> {
 5740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5741        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5742    }
 5743
 5744    fn do_completion(
 5745        &mut self,
 5746        item_ix: Option<usize>,
 5747        intent: CompletionIntent,
 5748        window: &mut Window,
 5749        cx: &mut Context<Editor>,
 5750    ) -> Option<Task<Result<()>>> {
 5751        use language::ToOffset as _;
 5752
 5753        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5754        else {
 5755            return None;
 5756        };
 5757
 5758        let candidate_id = {
 5759            let entries = completions_menu.entries.borrow();
 5760            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5761            if self.show_edit_predictions_in_menu() {
 5762                self.discard_edit_prediction(true, cx);
 5763            }
 5764            mat.candidate_id
 5765        };
 5766
 5767        let completion = completions_menu
 5768            .completions
 5769            .borrow()
 5770            .get(candidate_id)?
 5771            .clone();
 5772        cx.stop_propagation();
 5773
 5774        let buffer_handle = completions_menu.buffer.clone();
 5775
 5776        let CompletionEdit {
 5777            new_text,
 5778            snippet,
 5779            replace_range,
 5780        } = process_completion_for_edit(
 5781            &completion,
 5782            intent,
 5783            &buffer_handle,
 5784            &completions_menu.initial_position.text_anchor,
 5785            cx,
 5786        );
 5787
 5788        let buffer = buffer_handle.read(cx);
 5789        let snapshot = self.buffer.read(cx).snapshot(cx);
 5790        let newest_anchor = self.selections.newest_anchor();
 5791        let replace_range_multibuffer = {
 5792            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5793            excerpt.map_range_from_buffer(replace_range.clone())
 5794        };
 5795        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5796            return None;
 5797        }
 5798
 5799        let old_text = buffer
 5800            .text_for_range(replace_range.clone())
 5801            .collect::<String>();
 5802        let lookbehind = newest_anchor
 5803            .start
 5804            .text_anchor
 5805            .to_offset(buffer)
 5806            .saturating_sub(replace_range.start);
 5807        let lookahead = replace_range
 5808            .end
 5809            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5810        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5811        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5812
 5813        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5814        let mut ranges = Vec::new();
 5815        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5816
 5817        for selection in &selections {
 5818            let range = if selection.id == newest_anchor.id {
 5819                replace_range_multibuffer.clone()
 5820            } else {
 5821                let mut range = selection.range();
 5822
 5823                // if prefix is present, don't duplicate it
 5824                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5825                    range.start = range.start.saturating_sub(lookbehind);
 5826
 5827                    // if suffix is also present, mimic the newest cursor and replace it
 5828                    if selection.id != newest_anchor.id
 5829                        && snapshot.contains_str_at(range.end, suffix)
 5830                    {
 5831                        range.end += lookahead;
 5832                    }
 5833                }
 5834                range
 5835            };
 5836
 5837            ranges.push(range.clone());
 5838
 5839            if !self.linked_edit_ranges.is_empty() {
 5840                let start_anchor = snapshot.anchor_before(range.start);
 5841                let end_anchor = snapshot.anchor_after(range.end);
 5842                if let Some(ranges) = self
 5843                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5844                {
 5845                    for (buffer, edits) in ranges {
 5846                        linked_edits
 5847                            .entry(buffer.clone())
 5848                            .or_default()
 5849                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5850                    }
 5851                }
 5852            }
 5853        }
 5854
 5855        let common_prefix_len = old_text
 5856            .chars()
 5857            .zip(new_text.chars())
 5858            .take_while(|(a, b)| a == b)
 5859            .map(|(a, _)| a.len_utf8())
 5860            .sum::<usize>();
 5861
 5862        cx.emit(EditorEvent::InputHandled {
 5863            utf16_range_to_replace: None,
 5864            text: new_text[common_prefix_len..].into(),
 5865        });
 5866
 5867        self.transact(window, cx, |editor, window, cx| {
 5868            if let Some(mut snippet) = snippet {
 5869                snippet.text = new_text.to_string();
 5870                editor
 5871                    .insert_snippet(&ranges, snippet, window, cx)
 5872                    .log_err();
 5873            } else {
 5874                editor.buffer.update(cx, |multi_buffer, cx| {
 5875                    let auto_indent = match completion.insert_text_mode {
 5876                        Some(InsertTextMode::AS_IS) => None,
 5877                        _ => editor.autoindent_mode.clone(),
 5878                    };
 5879                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5880                    multi_buffer.edit(edits, auto_indent, cx);
 5881                });
 5882            }
 5883            for (buffer, edits) in linked_edits {
 5884                buffer.update(cx, |buffer, cx| {
 5885                    let snapshot = buffer.snapshot();
 5886                    let edits = edits
 5887                        .into_iter()
 5888                        .map(|(range, text)| {
 5889                            use text::ToPoint as TP;
 5890                            let end_point = TP::to_point(&range.end, &snapshot);
 5891                            let start_point = TP::to_point(&range.start, &snapshot);
 5892                            (start_point..end_point, text)
 5893                        })
 5894                        .sorted_by_key(|(range, _)| range.start);
 5895                    buffer.edit(edits, None, cx);
 5896                })
 5897            }
 5898
 5899            editor.refresh_edit_prediction(true, false, window, cx);
 5900        });
 5901        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 5902
 5903        let show_new_completions_on_confirm = completion
 5904            .confirm
 5905            .as_ref()
 5906            .is_some_and(|confirm| confirm(intent, window, cx));
 5907        if show_new_completions_on_confirm {
 5908            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5909        }
 5910
 5911        let provider = self.completion_provider.as_ref()?;
 5912        drop(completion);
 5913        let apply_edits = provider.apply_additional_edits_for_completion(
 5914            buffer_handle,
 5915            completions_menu.completions.clone(),
 5916            candidate_id,
 5917            true,
 5918            cx,
 5919        );
 5920
 5921        let editor_settings = EditorSettings::get_global(cx);
 5922        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5923            // After the code completion is finished, users often want to know what signatures are needed.
 5924            // so we should automatically call signature_help
 5925            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5926        }
 5927
 5928        Some(cx.foreground_executor().spawn(async move {
 5929            apply_edits.await?;
 5930            Ok(())
 5931        }))
 5932    }
 5933
 5934    pub fn toggle_code_actions(
 5935        &mut self,
 5936        action: &ToggleCodeActions,
 5937        window: &mut Window,
 5938        cx: &mut Context<Self>,
 5939    ) {
 5940        let quick_launch = action.quick_launch;
 5941        let mut context_menu = self.context_menu.borrow_mut();
 5942        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5943            if code_actions.deployed_from == action.deployed_from {
 5944                // Toggle if we're selecting the same one
 5945                *context_menu = None;
 5946                cx.notify();
 5947                return;
 5948            } else {
 5949                // Otherwise, clear it and start a new one
 5950                *context_menu = None;
 5951                cx.notify();
 5952            }
 5953        }
 5954        drop(context_menu);
 5955        let snapshot = self.snapshot(window, cx);
 5956        let deployed_from = action.deployed_from.clone();
 5957        let action = action.clone();
 5958        self.completion_tasks.clear();
 5959        self.discard_edit_prediction(false, cx);
 5960
 5961        let multibuffer_point = match &action.deployed_from {
 5962            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5963                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5964            }
 5965            _ => self
 5966                .selections
 5967                .newest::<Point>(&snapshot.display_snapshot)
 5968                .head(),
 5969        };
 5970        let Some((buffer, buffer_row)) = snapshot
 5971            .buffer_snapshot()
 5972            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5973            .and_then(|(buffer_snapshot, range)| {
 5974                self.buffer()
 5975                    .read(cx)
 5976                    .buffer(buffer_snapshot.remote_id())
 5977                    .map(|buffer| (buffer, range.start.row))
 5978            })
 5979        else {
 5980            return;
 5981        };
 5982        let buffer_id = buffer.read(cx).remote_id();
 5983        let tasks = self
 5984            .tasks
 5985            .get(&(buffer_id, buffer_row))
 5986            .map(|t| Arc::new(t.to_owned()));
 5987
 5988        if !self.focus_handle.is_focused(window) {
 5989            return;
 5990        }
 5991        let project = self.project.clone();
 5992
 5993        let code_actions_task = match deployed_from {
 5994            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5995            _ => self.code_actions(buffer_row, window, cx),
 5996        };
 5997
 5998        let runnable_task = match deployed_from {
 5999            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6000            _ => {
 6001                let mut task_context_task = Task::ready(None);
 6002                if let Some(tasks) = &tasks
 6003                    && let Some(project) = project
 6004                {
 6005                    task_context_task =
 6006                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6007                }
 6008
 6009                cx.spawn_in(window, {
 6010                    let buffer = buffer.clone();
 6011                    async move |editor, cx| {
 6012                        let task_context = task_context_task.await;
 6013
 6014                        let resolved_tasks =
 6015                            tasks
 6016                                .zip(task_context.clone())
 6017                                .map(|(tasks, task_context)| ResolvedTasks {
 6018                                    templates: tasks.resolve(&task_context).collect(),
 6019                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6020                                        multibuffer_point.row,
 6021                                        tasks.column,
 6022                                    )),
 6023                                });
 6024                        let debug_scenarios = editor
 6025                            .update(cx, |editor, cx| {
 6026                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6027                            })?
 6028                            .await;
 6029                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6030                    }
 6031                })
 6032            }
 6033        };
 6034
 6035        cx.spawn_in(window, async move |editor, cx| {
 6036            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6037            let code_actions = code_actions_task.await;
 6038            let spawn_straight_away = quick_launch
 6039                && resolved_tasks
 6040                    .as_ref()
 6041                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6042                && code_actions
 6043                    .as_ref()
 6044                    .is_none_or(|actions| actions.is_empty())
 6045                && debug_scenarios.is_empty();
 6046
 6047            editor.update_in(cx, |editor, window, cx| {
 6048                crate::hover_popover::hide_hover(editor, cx);
 6049                let actions = CodeActionContents::new(
 6050                    resolved_tasks,
 6051                    code_actions,
 6052                    debug_scenarios,
 6053                    task_context.unwrap_or_default(),
 6054                );
 6055
 6056                // Don't show the menu if there are no actions available
 6057                if actions.is_empty() {
 6058                    cx.notify();
 6059                    return Task::ready(Ok(()));
 6060                }
 6061
 6062                *editor.context_menu.borrow_mut() =
 6063                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6064                        buffer,
 6065                        actions,
 6066                        selected_item: Default::default(),
 6067                        scroll_handle: UniformListScrollHandle::default(),
 6068                        deployed_from,
 6069                    }));
 6070                cx.notify();
 6071                if spawn_straight_away
 6072                    && let Some(task) = editor.confirm_code_action(
 6073                        &ConfirmCodeAction { item_ix: Some(0) },
 6074                        window,
 6075                        cx,
 6076                    )
 6077                {
 6078                    return task;
 6079                }
 6080
 6081                Task::ready(Ok(()))
 6082            })
 6083        })
 6084        .detach_and_log_err(cx);
 6085    }
 6086
 6087    fn debug_scenarios(
 6088        &mut self,
 6089        resolved_tasks: &Option<ResolvedTasks>,
 6090        buffer: &Entity<Buffer>,
 6091        cx: &mut App,
 6092    ) -> Task<Vec<task::DebugScenario>> {
 6093        maybe!({
 6094            let project = self.project()?;
 6095            let dap_store = project.read(cx).dap_store();
 6096            let mut scenarios = vec![];
 6097            let resolved_tasks = resolved_tasks.as_ref()?;
 6098            let buffer = buffer.read(cx);
 6099            let language = buffer.language()?;
 6100            let file = buffer.file();
 6101            let debug_adapter = language_settings(language.name().into(), file, cx)
 6102                .debuggers
 6103                .first()
 6104                .map(SharedString::from)
 6105                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6106
 6107            dap_store.update(cx, |dap_store, cx| {
 6108                for (_, task) in &resolved_tasks.templates {
 6109                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6110                        task.original_task().clone(),
 6111                        debug_adapter.clone().into(),
 6112                        task.display_label().to_owned().into(),
 6113                        cx,
 6114                    );
 6115                    scenarios.push(maybe_scenario);
 6116                }
 6117            });
 6118            Some(cx.background_spawn(async move {
 6119                futures::future::join_all(scenarios)
 6120                    .await
 6121                    .into_iter()
 6122                    .flatten()
 6123                    .collect::<Vec<_>>()
 6124            }))
 6125        })
 6126        .unwrap_or_else(|| Task::ready(vec![]))
 6127    }
 6128
 6129    fn code_actions(
 6130        &mut self,
 6131        buffer_row: u32,
 6132        window: &mut Window,
 6133        cx: &mut Context<Self>,
 6134    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6135        let mut task = self.code_actions_task.take();
 6136        cx.spawn_in(window, async move |editor, cx| {
 6137            while let Some(prev_task) = task {
 6138                prev_task.await.log_err();
 6139                task = editor
 6140                    .update(cx, |this, _| this.code_actions_task.take())
 6141                    .ok()?;
 6142            }
 6143
 6144            editor
 6145                .update(cx, |editor, cx| {
 6146                    editor
 6147                        .available_code_actions
 6148                        .clone()
 6149                        .and_then(|(location, code_actions)| {
 6150                            let snapshot = location.buffer.read(cx).snapshot();
 6151                            let point_range = location.range.to_point(&snapshot);
 6152                            let point_range = point_range.start.row..=point_range.end.row;
 6153                            if point_range.contains(&buffer_row) {
 6154                                Some(code_actions)
 6155                            } else {
 6156                                None
 6157                            }
 6158                        })
 6159                })
 6160                .ok()
 6161                .flatten()
 6162        })
 6163    }
 6164
 6165    pub fn confirm_code_action(
 6166        &mut self,
 6167        action: &ConfirmCodeAction,
 6168        window: &mut Window,
 6169        cx: &mut Context<Self>,
 6170    ) -> Option<Task<Result<()>>> {
 6171        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6172
 6173        let actions_menu =
 6174            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6175                menu
 6176            } else {
 6177                return None;
 6178            };
 6179
 6180        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6181        let action = actions_menu.actions.get(action_ix)?;
 6182        let title = action.label();
 6183        let buffer = actions_menu.buffer;
 6184        let workspace = self.workspace()?;
 6185
 6186        match action {
 6187            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6188                workspace.update(cx, |workspace, cx| {
 6189                    workspace.schedule_resolved_task(
 6190                        task_source_kind,
 6191                        resolved_task,
 6192                        false,
 6193                        window,
 6194                        cx,
 6195                    );
 6196
 6197                    Some(Task::ready(Ok(())))
 6198                })
 6199            }
 6200            CodeActionsItem::CodeAction {
 6201                excerpt_id,
 6202                action,
 6203                provider,
 6204            } => {
 6205                let apply_code_action =
 6206                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6207                let workspace = workspace.downgrade();
 6208                Some(cx.spawn_in(window, async move |editor, cx| {
 6209                    let project_transaction = apply_code_action.await?;
 6210                    Self::open_project_transaction(
 6211                        &editor,
 6212                        workspace,
 6213                        project_transaction,
 6214                        title,
 6215                        cx,
 6216                    )
 6217                    .await
 6218                }))
 6219            }
 6220            CodeActionsItem::DebugScenario(scenario) => {
 6221                let context = actions_menu.actions.context;
 6222
 6223                workspace.update(cx, |workspace, cx| {
 6224                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6225                    workspace.start_debug_session(
 6226                        scenario,
 6227                        context,
 6228                        Some(buffer),
 6229                        None,
 6230                        window,
 6231                        cx,
 6232                    );
 6233                });
 6234                Some(Task::ready(Ok(())))
 6235            }
 6236        }
 6237    }
 6238
 6239    pub async fn open_project_transaction(
 6240        editor: &WeakEntity<Editor>,
 6241        workspace: WeakEntity<Workspace>,
 6242        transaction: ProjectTransaction,
 6243        title: String,
 6244        cx: &mut AsyncWindowContext,
 6245    ) -> Result<()> {
 6246        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6247        cx.update(|_, cx| {
 6248            entries.sort_unstable_by_key(|(buffer, _)| {
 6249                buffer.read(cx).file().map(|f| f.path().clone())
 6250            });
 6251        })?;
 6252        if entries.is_empty() {
 6253            return Ok(());
 6254        }
 6255
 6256        // If the project transaction's edits are all contained within this editor, then
 6257        // avoid opening a new editor to display them.
 6258
 6259        if let [(buffer, transaction)] = &*entries {
 6260            let excerpt = editor.update(cx, |editor, cx| {
 6261                editor
 6262                    .buffer()
 6263                    .read(cx)
 6264                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6265            })?;
 6266            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6267                && excerpted_buffer == *buffer
 6268            {
 6269                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6270                    let excerpt_range = excerpt_range.to_offset(buffer);
 6271                    buffer
 6272                        .edited_ranges_for_transaction::<usize>(transaction)
 6273                        .all(|range| {
 6274                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6275                        })
 6276                })?;
 6277
 6278                if all_edits_within_excerpt {
 6279                    return Ok(());
 6280                }
 6281            }
 6282        }
 6283
 6284        let mut ranges_to_highlight = Vec::new();
 6285        let excerpt_buffer = cx.new(|cx| {
 6286            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6287            for (buffer_handle, transaction) in &entries {
 6288                let edited_ranges = buffer_handle
 6289                    .read(cx)
 6290                    .edited_ranges_for_transaction::<Point>(transaction)
 6291                    .collect::<Vec<_>>();
 6292                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6293                    PathKey::for_buffer(buffer_handle, cx),
 6294                    buffer_handle.clone(),
 6295                    edited_ranges,
 6296                    multibuffer_context_lines(cx),
 6297                    cx,
 6298                );
 6299
 6300                ranges_to_highlight.extend(ranges);
 6301            }
 6302            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6303            multibuffer
 6304        })?;
 6305
 6306        workspace.update_in(cx, |workspace, window, cx| {
 6307            let project = workspace.project().clone();
 6308            let editor =
 6309                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6310            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6311            editor.update(cx, |editor, cx| {
 6312                editor.highlight_background::<Self>(
 6313                    &ranges_to_highlight,
 6314                    |theme| theme.colors().editor_highlighted_line_background,
 6315                    cx,
 6316                );
 6317            });
 6318        })?;
 6319
 6320        Ok(())
 6321    }
 6322
 6323    pub fn clear_code_action_providers(&mut self) {
 6324        self.code_action_providers.clear();
 6325        self.available_code_actions.take();
 6326    }
 6327
 6328    pub fn add_code_action_provider(
 6329        &mut self,
 6330        provider: Rc<dyn CodeActionProvider>,
 6331        window: &mut Window,
 6332        cx: &mut Context<Self>,
 6333    ) {
 6334        if self
 6335            .code_action_providers
 6336            .iter()
 6337            .any(|existing_provider| existing_provider.id() == provider.id())
 6338        {
 6339            return;
 6340        }
 6341
 6342        self.code_action_providers.push(provider);
 6343        self.refresh_code_actions(window, cx);
 6344    }
 6345
 6346    pub fn remove_code_action_provider(
 6347        &mut self,
 6348        id: Arc<str>,
 6349        window: &mut Window,
 6350        cx: &mut Context<Self>,
 6351    ) {
 6352        self.code_action_providers
 6353            .retain(|provider| provider.id() != id);
 6354        self.refresh_code_actions(window, cx);
 6355    }
 6356
 6357    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6358        !self.code_action_providers.is_empty()
 6359            && EditorSettings::get_global(cx).toolbar.code_actions
 6360    }
 6361
 6362    pub fn has_available_code_actions(&self) -> bool {
 6363        self.available_code_actions
 6364            .as_ref()
 6365            .is_some_and(|(_, actions)| !actions.is_empty())
 6366    }
 6367
 6368    fn render_inline_code_actions(
 6369        &self,
 6370        icon_size: ui::IconSize,
 6371        display_row: DisplayRow,
 6372        is_active: bool,
 6373        cx: &mut Context<Self>,
 6374    ) -> AnyElement {
 6375        let show_tooltip = !self.context_menu_visible();
 6376        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6377            .icon_size(icon_size)
 6378            .shape(ui::IconButtonShape::Square)
 6379            .icon_color(ui::Color::Hidden)
 6380            .toggle_state(is_active)
 6381            .when(show_tooltip, |this| {
 6382                this.tooltip({
 6383                    let focus_handle = self.focus_handle.clone();
 6384                    move |_window, cx| {
 6385                        Tooltip::for_action_in(
 6386                            "Toggle Code Actions",
 6387                            &ToggleCodeActions {
 6388                                deployed_from: None,
 6389                                quick_launch: false,
 6390                            },
 6391                            &focus_handle,
 6392                            cx,
 6393                        )
 6394                    }
 6395                })
 6396            })
 6397            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6398                window.focus(&editor.focus_handle(cx));
 6399                editor.toggle_code_actions(
 6400                    &crate::actions::ToggleCodeActions {
 6401                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6402                            display_row,
 6403                        )),
 6404                        quick_launch: false,
 6405                    },
 6406                    window,
 6407                    cx,
 6408                );
 6409            }))
 6410            .into_any_element()
 6411    }
 6412
 6413    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6414        &self.context_menu
 6415    }
 6416
 6417    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6418        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6419            cx.background_executor()
 6420                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6421                .await;
 6422
 6423            let (start_buffer, start, _, end, newest_selection) = this
 6424                .update(cx, |this, cx| {
 6425                    let newest_selection = this.selections.newest_anchor().clone();
 6426                    if newest_selection.head().diff_base_anchor.is_some() {
 6427                        return None;
 6428                    }
 6429                    let display_snapshot = this.display_snapshot(cx);
 6430                    let newest_selection_adjusted =
 6431                        this.selections.newest_adjusted(&display_snapshot);
 6432                    let buffer = this.buffer.read(cx);
 6433
 6434                    let (start_buffer, start) =
 6435                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6436                    let (end_buffer, end) =
 6437                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6438
 6439                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6440                })?
 6441                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6442                .context(
 6443                    "Expected selection to lie in a single buffer when refreshing code actions",
 6444                )?;
 6445            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6446                let providers = this.code_action_providers.clone();
 6447                let tasks = this
 6448                    .code_action_providers
 6449                    .iter()
 6450                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6451                    .collect::<Vec<_>>();
 6452                (providers, tasks)
 6453            })?;
 6454
 6455            let mut actions = Vec::new();
 6456            for (provider, provider_actions) in
 6457                providers.into_iter().zip(future::join_all(tasks).await)
 6458            {
 6459                if let Some(provider_actions) = provider_actions.log_err() {
 6460                    actions.extend(provider_actions.into_iter().map(|action| {
 6461                        AvailableCodeAction {
 6462                            excerpt_id: newest_selection.start.excerpt_id,
 6463                            action,
 6464                            provider: provider.clone(),
 6465                        }
 6466                    }));
 6467                }
 6468            }
 6469
 6470            this.update(cx, |this, cx| {
 6471                this.available_code_actions = if actions.is_empty() {
 6472                    None
 6473                } else {
 6474                    Some((
 6475                        Location {
 6476                            buffer: start_buffer,
 6477                            range: start..end,
 6478                        },
 6479                        actions.into(),
 6480                    ))
 6481                };
 6482                cx.notify();
 6483            })
 6484        }));
 6485    }
 6486
 6487    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6488        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6489            self.show_git_blame_inline = false;
 6490
 6491            self.show_git_blame_inline_delay_task =
 6492                Some(cx.spawn_in(window, async move |this, cx| {
 6493                    cx.background_executor().timer(delay).await;
 6494
 6495                    this.update(cx, |this, cx| {
 6496                        this.show_git_blame_inline = true;
 6497                        cx.notify();
 6498                    })
 6499                    .log_err();
 6500                }));
 6501        }
 6502    }
 6503
 6504    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6505        let snapshot = self.snapshot(window, cx);
 6506        let cursor = self
 6507            .selections
 6508            .newest::<Point>(&snapshot.display_snapshot)
 6509            .head();
 6510        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6511        else {
 6512            return;
 6513        };
 6514
 6515        let Some(blame) = self.blame.as_ref() else {
 6516            return;
 6517        };
 6518
 6519        let row_info = RowInfo {
 6520            buffer_id: Some(buffer.remote_id()),
 6521            buffer_row: Some(point.row),
 6522            ..Default::default()
 6523        };
 6524        let Some((buffer, blame_entry)) = blame
 6525            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6526            .flatten()
 6527        else {
 6528            return;
 6529        };
 6530
 6531        let anchor = self.selections.newest_anchor().head();
 6532        let position = self.to_pixel_point(anchor, &snapshot, window);
 6533        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6534            self.show_blame_popover(
 6535                buffer,
 6536                &blame_entry,
 6537                position + last_bounds.origin,
 6538                true,
 6539                cx,
 6540            );
 6541        };
 6542    }
 6543
 6544    fn show_blame_popover(
 6545        &mut self,
 6546        buffer: BufferId,
 6547        blame_entry: &BlameEntry,
 6548        position: gpui::Point<Pixels>,
 6549        ignore_timeout: bool,
 6550        cx: &mut Context<Self>,
 6551    ) {
 6552        if let Some(state) = &mut self.inline_blame_popover {
 6553            state.hide_task.take();
 6554        } else {
 6555            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6556            let blame_entry = blame_entry.clone();
 6557            let show_task = cx.spawn(async move |editor, cx| {
 6558                if !ignore_timeout {
 6559                    cx.background_executor()
 6560                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6561                        .await;
 6562                }
 6563                editor
 6564                    .update(cx, |editor, cx| {
 6565                        editor.inline_blame_popover_show_task.take();
 6566                        let Some(blame) = editor.blame.as_ref() else {
 6567                            return;
 6568                        };
 6569                        let blame = blame.read(cx);
 6570                        let details = blame.details_for_entry(buffer, &blame_entry);
 6571                        let markdown = cx.new(|cx| {
 6572                            Markdown::new(
 6573                                details
 6574                                    .as_ref()
 6575                                    .map(|message| message.message.clone())
 6576                                    .unwrap_or_default(),
 6577                                None,
 6578                                None,
 6579                                cx,
 6580                            )
 6581                        });
 6582                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6583                            position,
 6584                            hide_task: None,
 6585                            popover_bounds: None,
 6586                            popover_state: InlineBlamePopoverState {
 6587                                scroll_handle: ScrollHandle::new(),
 6588                                commit_message: details,
 6589                                markdown,
 6590                            },
 6591                            keyboard_grace: ignore_timeout,
 6592                        });
 6593                        cx.notify();
 6594                    })
 6595                    .ok();
 6596            });
 6597            self.inline_blame_popover_show_task = Some(show_task);
 6598        }
 6599    }
 6600
 6601    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6602        self.inline_blame_popover_show_task.take();
 6603        if let Some(state) = &mut self.inline_blame_popover {
 6604            let hide_task = cx.spawn(async move |editor, cx| {
 6605                if !ignore_timeout {
 6606                    cx.background_executor()
 6607                        .timer(std::time::Duration::from_millis(100))
 6608                        .await;
 6609                }
 6610                editor
 6611                    .update(cx, |editor, cx| {
 6612                        editor.inline_blame_popover.take();
 6613                        cx.notify();
 6614                    })
 6615                    .ok();
 6616            });
 6617            state.hide_task = Some(hide_task);
 6618            true
 6619        } else {
 6620            false
 6621        }
 6622    }
 6623
 6624    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6625        if self.pending_rename.is_some() {
 6626            return None;
 6627        }
 6628
 6629        let provider = self.semantics_provider.clone()?;
 6630        let buffer = self.buffer.read(cx);
 6631        let newest_selection = self.selections.newest_anchor().clone();
 6632        let cursor_position = newest_selection.head();
 6633        let (cursor_buffer, cursor_buffer_position) =
 6634            buffer.text_anchor_for_position(cursor_position, cx)?;
 6635        let (tail_buffer, tail_buffer_position) =
 6636            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6637        if cursor_buffer != tail_buffer {
 6638            return None;
 6639        }
 6640
 6641        let snapshot = cursor_buffer.read(cx).snapshot();
 6642        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6643        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6644        if start_word_range != end_word_range {
 6645            self.document_highlights_task.take();
 6646            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6647            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6648            return None;
 6649        }
 6650
 6651        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6652        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6653            cx.background_executor()
 6654                .timer(Duration::from_millis(debounce))
 6655                .await;
 6656
 6657            let highlights = if let Some(highlights) = cx
 6658                .update(|cx| {
 6659                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6660                })
 6661                .ok()
 6662                .flatten()
 6663            {
 6664                highlights.await.log_err()
 6665            } else {
 6666                None
 6667            };
 6668
 6669            if let Some(highlights) = highlights {
 6670                this.update(cx, |this, cx| {
 6671                    if this.pending_rename.is_some() {
 6672                        return;
 6673                    }
 6674
 6675                    let buffer = this.buffer.read(cx);
 6676                    if buffer
 6677                        .text_anchor_for_position(cursor_position, cx)
 6678                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6679                    {
 6680                        return;
 6681                    }
 6682
 6683                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6684                    let mut write_ranges = Vec::new();
 6685                    let mut read_ranges = Vec::new();
 6686                    for highlight in highlights {
 6687                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6688                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6689                        {
 6690                            let start = highlight
 6691                                .range
 6692                                .start
 6693                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6694                            let end = highlight
 6695                                .range
 6696                                .end
 6697                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6698                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6699                                continue;
 6700                            }
 6701
 6702                            let range =
 6703                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6704                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6705                                write_ranges.push(range);
 6706                            } else {
 6707                                read_ranges.push(range);
 6708                            }
 6709                        }
 6710                    }
 6711
 6712                    this.highlight_background::<DocumentHighlightRead>(
 6713                        &read_ranges,
 6714                        |theme| theme.colors().editor_document_highlight_read_background,
 6715                        cx,
 6716                    );
 6717                    this.highlight_background::<DocumentHighlightWrite>(
 6718                        &write_ranges,
 6719                        |theme| theme.colors().editor_document_highlight_write_background,
 6720                        cx,
 6721                    );
 6722                    cx.notify();
 6723                })
 6724                .log_err();
 6725            }
 6726        }));
 6727        None
 6728    }
 6729
 6730    fn prepare_highlight_query_from_selection(
 6731        &mut self,
 6732        window: &Window,
 6733        cx: &mut Context<Editor>,
 6734    ) -> Option<(String, Range<Anchor>)> {
 6735        if matches!(self.mode, EditorMode::SingleLine) {
 6736            return None;
 6737        }
 6738        if !EditorSettings::get_global(cx).selection_highlight {
 6739            return None;
 6740        }
 6741        if self.selections.count() != 1 || self.selections.line_mode() {
 6742            return None;
 6743        }
 6744        let snapshot = self.snapshot(window, cx);
 6745        let selection = self.selections.newest::<Point>(&snapshot);
 6746        // If the selection spans multiple rows OR it is empty
 6747        if selection.start.row != selection.end.row
 6748            || selection.start.column == selection.end.column
 6749        {
 6750            return None;
 6751        }
 6752        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6753        let query = snapshot
 6754            .buffer_snapshot()
 6755            .text_for_range(selection_anchor_range.clone())
 6756            .collect::<String>();
 6757        if query.trim().is_empty() {
 6758            return None;
 6759        }
 6760        Some((query, selection_anchor_range))
 6761    }
 6762
 6763    fn update_selection_occurrence_highlights(
 6764        &mut self,
 6765        query_text: String,
 6766        query_range: Range<Anchor>,
 6767        multi_buffer_range_to_query: Range<Point>,
 6768        use_debounce: bool,
 6769        window: &mut Window,
 6770        cx: &mut Context<Editor>,
 6771    ) -> Task<()> {
 6772        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6773        cx.spawn_in(window, async move |editor, cx| {
 6774            if use_debounce {
 6775                cx.background_executor()
 6776                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6777                    .await;
 6778            }
 6779            let match_task = cx.background_spawn(async move {
 6780                let buffer_ranges = multi_buffer_snapshot
 6781                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6782                    .into_iter()
 6783                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6784                let mut match_ranges = Vec::new();
 6785                let Ok(regex) = project::search::SearchQuery::text(
 6786                    query_text.clone(),
 6787                    false,
 6788                    false,
 6789                    false,
 6790                    Default::default(),
 6791                    Default::default(),
 6792                    false,
 6793                    None,
 6794                ) else {
 6795                    return Vec::default();
 6796                };
 6797                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6798                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6799                    match_ranges.extend(
 6800                        regex
 6801                            .search(buffer_snapshot, Some(search_range.clone()))
 6802                            .await
 6803                            .into_iter()
 6804                            .filter_map(|match_range| {
 6805                                let match_start = buffer_snapshot
 6806                                    .anchor_after(search_range.start + match_range.start);
 6807                                let match_end = buffer_snapshot
 6808                                    .anchor_before(search_range.start + match_range.end);
 6809                                let match_anchor_range = Anchor::range_in_buffer(
 6810                                    excerpt_id,
 6811                                    buffer_snapshot.remote_id(),
 6812                                    match_start..match_end,
 6813                                );
 6814                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6815                            }),
 6816                    );
 6817                }
 6818                match_ranges
 6819            });
 6820            let match_ranges = match_task.await;
 6821            editor
 6822                .update_in(cx, |editor, _, cx| {
 6823                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6824                    if !match_ranges.is_empty() {
 6825                        editor.highlight_background::<SelectedTextHighlight>(
 6826                            &match_ranges,
 6827                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6828                            cx,
 6829                        )
 6830                    }
 6831                })
 6832                .log_err();
 6833        })
 6834    }
 6835
 6836    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6837        struct NewlineFold;
 6838        let type_id = std::any::TypeId::of::<NewlineFold>();
 6839        if !self.mode.is_single_line() {
 6840            return;
 6841        }
 6842        let snapshot = self.snapshot(window, cx);
 6843        if snapshot.buffer_snapshot().max_point().row == 0 {
 6844            return;
 6845        }
 6846        let task = cx.background_spawn(async move {
 6847            let new_newlines = snapshot
 6848                .buffer_chars_at(0)
 6849                .filter_map(|(c, i)| {
 6850                    if c == '\n' {
 6851                        Some(
 6852                            snapshot.buffer_snapshot().anchor_after(i)
 6853                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6854                        )
 6855                    } else {
 6856                        None
 6857                    }
 6858                })
 6859                .collect::<Vec<_>>();
 6860            let existing_newlines = snapshot
 6861                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6862                .filter_map(|fold| {
 6863                    if fold.placeholder.type_tag == Some(type_id) {
 6864                        Some(fold.range.start..fold.range.end)
 6865                    } else {
 6866                        None
 6867                    }
 6868                })
 6869                .collect::<Vec<_>>();
 6870
 6871            (new_newlines, existing_newlines)
 6872        });
 6873        self.folding_newlines = cx.spawn(async move |this, cx| {
 6874            let (new_newlines, existing_newlines) = task.await;
 6875            if new_newlines == existing_newlines {
 6876                return;
 6877            }
 6878            let placeholder = FoldPlaceholder {
 6879                render: Arc::new(move |_, _, cx| {
 6880                    div()
 6881                        .bg(cx.theme().status().hint_background)
 6882                        .border_b_1()
 6883                        .size_full()
 6884                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6885                        .border_color(cx.theme().status().hint)
 6886                        .child("\\n")
 6887                        .into_any()
 6888                }),
 6889                constrain_width: false,
 6890                merge_adjacent: false,
 6891                type_tag: Some(type_id),
 6892            };
 6893            let creases = new_newlines
 6894                .into_iter()
 6895                .map(|range| Crease::simple(range, placeholder.clone()))
 6896                .collect();
 6897            this.update(cx, |this, cx| {
 6898                this.display_map.update(cx, |display_map, cx| {
 6899                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6900                    display_map.fold(creases, cx);
 6901                });
 6902            })
 6903            .ok();
 6904        });
 6905    }
 6906
 6907    fn refresh_selected_text_highlights(
 6908        &mut self,
 6909        on_buffer_edit: bool,
 6910        window: &mut Window,
 6911        cx: &mut Context<Editor>,
 6912    ) {
 6913        let Some((query_text, query_range)) =
 6914            self.prepare_highlight_query_from_selection(window, cx)
 6915        else {
 6916            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6917            self.quick_selection_highlight_task.take();
 6918            self.debounced_selection_highlight_task.take();
 6919            return;
 6920        };
 6921        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6922        if on_buffer_edit
 6923            || self
 6924                .quick_selection_highlight_task
 6925                .as_ref()
 6926                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6927        {
 6928            let multi_buffer_visible_start = self
 6929                .scroll_manager
 6930                .anchor()
 6931                .anchor
 6932                .to_point(&multi_buffer_snapshot);
 6933            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6934                multi_buffer_visible_start
 6935                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6936                Bias::Left,
 6937            );
 6938            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6939            self.quick_selection_highlight_task = Some((
 6940                query_range.clone(),
 6941                self.update_selection_occurrence_highlights(
 6942                    query_text.clone(),
 6943                    query_range.clone(),
 6944                    multi_buffer_visible_range,
 6945                    false,
 6946                    window,
 6947                    cx,
 6948                ),
 6949            ));
 6950        }
 6951        if on_buffer_edit
 6952            || self
 6953                .debounced_selection_highlight_task
 6954                .as_ref()
 6955                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6956        {
 6957            let multi_buffer_start = multi_buffer_snapshot
 6958                .anchor_before(0)
 6959                .to_point(&multi_buffer_snapshot);
 6960            let multi_buffer_end = multi_buffer_snapshot
 6961                .anchor_after(multi_buffer_snapshot.len())
 6962                .to_point(&multi_buffer_snapshot);
 6963            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6964            self.debounced_selection_highlight_task = Some((
 6965                query_range.clone(),
 6966                self.update_selection_occurrence_highlights(
 6967                    query_text,
 6968                    query_range,
 6969                    multi_buffer_full_range,
 6970                    true,
 6971                    window,
 6972                    cx,
 6973                ),
 6974            ));
 6975        }
 6976    }
 6977
 6978    pub fn refresh_edit_prediction(
 6979        &mut self,
 6980        debounce: bool,
 6981        user_requested: bool,
 6982        window: &mut Window,
 6983        cx: &mut Context<Self>,
 6984    ) -> Option<()> {
 6985        if DisableAiSettings::get_global(cx).disable_ai {
 6986            return None;
 6987        }
 6988
 6989        let provider = self.edit_prediction_provider()?;
 6990        let cursor = self.selections.newest_anchor().head();
 6991        let (buffer, cursor_buffer_position) =
 6992            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6993
 6994        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6995            self.discard_edit_prediction(false, cx);
 6996            return None;
 6997        }
 6998
 6999        self.update_visible_edit_prediction(window, cx);
 7000
 7001        if !user_requested
 7002            && (!self.should_show_edit_predictions()
 7003                || !self.is_focused(window)
 7004                || buffer.read(cx).is_empty())
 7005        {
 7006            self.discard_edit_prediction(false, cx);
 7007            return None;
 7008        }
 7009
 7010        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7011        Some(())
 7012    }
 7013
 7014    fn show_edit_predictions_in_menu(&self) -> bool {
 7015        match self.edit_prediction_settings {
 7016            EditPredictionSettings::Disabled => false,
 7017            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7018        }
 7019    }
 7020
 7021    pub fn edit_predictions_enabled(&self) -> bool {
 7022        match self.edit_prediction_settings {
 7023            EditPredictionSettings::Disabled => false,
 7024            EditPredictionSettings::Enabled { .. } => true,
 7025        }
 7026    }
 7027
 7028    fn edit_prediction_requires_modifier(&self) -> bool {
 7029        match self.edit_prediction_settings {
 7030            EditPredictionSettings::Disabled => false,
 7031            EditPredictionSettings::Enabled {
 7032                preview_requires_modifier,
 7033                ..
 7034            } => preview_requires_modifier,
 7035        }
 7036    }
 7037
 7038    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7039        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7040            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7041            self.discard_edit_prediction(false, cx);
 7042        } else {
 7043            let selection = self.selections.newest_anchor();
 7044            let cursor = selection.head();
 7045
 7046            if let Some((buffer, cursor_buffer_position)) =
 7047                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7048            {
 7049                self.edit_prediction_settings =
 7050                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7051            }
 7052        }
 7053    }
 7054
 7055    fn edit_prediction_settings_at_position(
 7056        &self,
 7057        buffer: &Entity<Buffer>,
 7058        buffer_position: language::Anchor,
 7059        cx: &App,
 7060    ) -> EditPredictionSettings {
 7061        if !self.mode.is_full()
 7062            || !self.show_edit_predictions_override.unwrap_or(true)
 7063            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7064        {
 7065            return EditPredictionSettings::Disabled;
 7066        }
 7067
 7068        let buffer = buffer.read(cx);
 7069
 7070        let file = buffer.file();
 7071
 7072        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7073            return EditPredictionSettings::Disabled;
 7074        };
 7075
 7076        let by_provider = matches!(
 7077            self.menu_edit_predictions_policy,
 7078            MenuEditPredictionsPolicy::ByProvider
 7079        );
 7080
 7081        let show_in_menu = by_provider
 7082            && self
 7083                .edit_prediction_provider
 7084                .as_ref()
 7085                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7086
 7087        let preview_requires_modifier =
 7088            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7089
 7090        EditPredictionSettings::Enabled {
 7091            show_in_menu,
 7092            preview_requires_modifier,
 7093        }
 7094    }
 7095
 7096    fn should_show_edit_predictions(&self) -> bool {
 7097        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7098    }
 7099
 7100    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7101        matches!(
 7102            self.edit_prediction_preview,
 7103            EditPredictionPreview::Active { .. }
 7104        )
 7105    }
 7106
 7107    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7108        let cursor = self.selections.newest_anchor().head();
 7109        if let Some((buffer, cursor_position)) =
 7110            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7111        {
 7112            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7113        } else {
 7114            false
 7115        }
 7116    }
 7117
 7118    pub fn supports_minimap(&self, cx: &App) -> bool {
 7119        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7120    }
 7121
 7122    fn edit_predictions_enabled_in_buffer(
 7123        &self,
 7124        buffer: &Entity<Buffer>,
 7125        buffer_position: language::Anchor,
 7126        cx: &App,
 7127    ) -> bool {
 7128        maybe!({
 7129            if self.read_only(cx) {
 7130                return Some(false);
 7131            }
 7132            let provider = self.edit_prediction_provider()?;
 7133            if !provider.is_enabled(buffer, buffer_position, cx) {
 7134                return Some(false);
 7135            }
 7136            let buffer = buffer.read(cx);
 7137            let Some(file) = buffer.file() else {
 7138                return Some(true);
 7139            };
 7140            let settings = all_language_settings(Some(file), cx);
 7141            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7142        })
 7143        .unwrap_or(false)
 7144    }
 7145
 7146    fn cycle_edit_prediction(
 7147        &mut self,
 7148        direction: Direction,
 7149        window: &mut Window,
 7150        cx: &mut Context<Self>,
 7151    ) -> Option<()> {
 7152        let provider = self.edit_prediction_provider()?;
 7153        let cursor = self.selections.newest_anchor().head();
 7154        let (buffer, cursor_buffer_position) =
 7155            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7156        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7157            return None;
 7158        }
 7159
 7160        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7161        self.update_visible_edit_prediction(window, cx);
 7162
 7163        Some(())
 7164    }
 7165
 7166    pub fn show_edit_prediction(
 7167        &mut self,
 7168        _: &ShowEditPrediction,
 7169        window: &mut Window,
 7170        cx: &mut Context<Self>,
 7171    ) {
 7172        if !self.has_active_edit_prediction() {
 7173            self.refresh_edit_prediction(false, true, window, cx);
 7174            return;
 7175        }
 7176
 7177        self.update_visible_edit_prediction(window, cx);
 7178    }
 7179
 7180    pub fn display_cursor_names(
 7181        &mut self,
 7182        _: &DisplayCursorNames,
 7183        window: &mut Window,
 7184        cx: &mut Context<Self>,
 7185    ) {
 7186        self.show_cursor_names(window, cx);
 7187    }
 7188
 7189    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7190        self.show_cursor_names = true;
 7191        cx.notify();
 7192        cx.spawn_in(window, async move |this, cx| {
 7193            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7194            this.update(cx, |this, cx| {
 7195                this.show_cursor_names = false;
 7196                cx.notify()
 7197            })
 7198            .ok()
 7199        })
 7200        .detach();
 7201    }
 7202
 7203    pub fn next_edit_prediction(
 7204        &mut self,
 7205        _: &NextEditPrediction,
 7206        window: &mut Window,
 7207        cx: &mut Context<Self>,
 7208    ) {
 7209        if self.has_active_edit_prediction() {
 7210            self.cycle_edit_prediction(Direction::Next, window, cx);
 7211        } else {
 7212            let is_copilot_disabled = self
 7213                .refresh_edit_prediction(false, true, window, cx)
 7214                .is_none();
 7215            if is_copilot_disabled {
 7216                cx.propagate();
 7217            }
 7218        }
 7219    }
 7220
 7221    pub fn previous_edit_prediction(
 7222        &mut self,
 7223        _: &PreviousEditPrediction,
 7224        window: &mut Window,
 7225        cx: &mut Context<Self>,
 7226    ) {
 7227        if self.has_active_edit_prediction() {
 7228            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7229        } else {
 7230            let is_copilot_disabled = self
 7231                .refresh_edit_prediction(false, true, window, cx)
 7232                .is_none();
 7233            if is_copilot_disabled {
 7234                cx.propagate();
 7235            }
 7236        }
 7237    }
 7238
 7239    pub fn accept_edit_prediction(
 7240        &mut self,
 7241        _: &AcceptEditPrediction,
 7242        window: &mut Window,
 7243        cx: &mut Context<Self>,
 7244    ) {
 7245        if self.show_edit_predictions_in_menu() {
 7246            self.hide_context_menu(window, cx);
 7247        }
 7248
 7249        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7250            return;
 7251        };
 7252
 7253        match &active_edit_prediction.completion {
 7254            EditPrediction::MoveWithin { target, .. } => {
 7255                let target = *target;
 7256
 7257                if let Some(position_map) = &self.last_position_map {
 7258                    if position_map
 7259                        .visible_row_range
 7260                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7261                        || !self.edit_prediction_requires_modifier()
 7262                    {
 7263                        self.unfold_ranges(&[target..target], true, false, cx);
 7264                        // Note that this is also done in vim's handler of the Tab action.
 7265                        self.change_selections(
 7266                            SelectionEffects::scroll(Autoscroll::newest()),
 7267                            window,
 7268                            cx,
 7269                            |selections| {
 7270                                selections.select_anchor_ranges([target..target]);
 7271                            },
 7272                        );
 7273                        self.clear_row_highlights::<EditPredictionPreview>();
 7274
 7275                        self.edit_prediction_preview
 7276                            .set_previous_scroll_position(None);
 7277                    } else {
 7278                        self.edit_prediction_preview
 7279                            .set_previous_scroll_position(Some(
 7280                                position_map.snapshot.scroll_anchor,
 7281                            ));
 7282
 7283                        self.highlight_rows::<EditPredictionPreview>(
 7284                            target..target,
 7285                            cx.theme().colors().editor_highlighted_line_background,
 7286                            RowHighlightOptions {
 7287                                autoscroll: true,
 7288                                ..Default::default()
 7289                            },
 7290                            cx,
 7291                        );
 7292                        self.request_autoscroll(Autoscroll::fit(), cx);
 7293                    }
 7294                }
 7295            }
 7296            EditPrediction::MoveOutside { snapshot, target } => {
 7297                if let Some(workspace) = self.workspace() {
 7298                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7299                        .detach_and_log_err(cx);
 7300                }
 7301            }
 7302            EditPrediction::Edit { edits, .. } => {
 7303                self.report_edit_prediction_event(
 7304                    active_edit_prediction.completion_id.clone(),
 7305                    true,
 7306                    cx,
 7307                );
 7308
 7309                if let Some(provider) = self.edit_prediction_provider() {
 7310                    provider.accept(cx);
 7311                }
 7312
 7313                // Store the transaction ID and selections before applying the edit
 7314                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7315
 7316                let snapshot = self.buffer.read(cx).snapshot(cx);
 7317                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7318
 7319                self.buffer.update(cx, |buffer, cx| {
 7320                    buffer.edit(edits.iter().cloned(), None, cx)
 7321                });
 7322
 7323                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7324                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7325                });
 7326
 7327                let selections = self.selections.disjoint_anchors_arc();
 7328                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7329                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7330                    if has_new_transaction {
 7331                        self.selection_history
 7332                            .insert_transaction(transaction_id_now, selections);
 7333                    }
 7334                }
 7335
 7336                self.update_visible_edit_prediction(window, cx);
 7337                if self.active_edit_prediction.is_none() {
 7338                    self.refresh_edit_prediction(true, true, window, cx);
 7339                }
 7340
 7341                cx.notify();
 7342            }
 7343        }
 7344
 7345        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7346    }
 7347
 7348    pub fn accept_partial_edit_prediction(
 7349        &mut self,
 7350        _: &AcceptPartialEditPrediction,
 7351        window: &mut Window,
 7352        cx: &mut Context<Self>,
 7353    ) {
 7354        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7355            return;
 7356        };
 7357        if self.selections.count() != 1 {
 7358            return;
 7359        }
 7360
 7361        match &active_edit_prediction.completion {
 7362            EditPrediction::MoveWithin { target, .. } => {
 7363                let target = *target;
 7364                self.change_selections(
 7365                    SelectionEffects::scroll(Autoscroll::newest()),
 7366                    window,
 7367                    cx,
 7368                    |selections| {
 7369                        selections.select_anchor_ranges([target..target]);
 7370                    },
 7371                );
 7372            }
 7373            EditPrediction::MoveOutside { snapshot, target } => {
 7374                if let Some(workspace) = self.workspace() {
 7375                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7376                        .detach_and_log_err(cx);
 7377                }
 7378            }
 7379            EditPrediction::Edit { edits, .. } => {
 7380                self.report_edit_prediction_event(
 7381                    active_edit_prediction.completion_id.clone(),
 7382                    true,
 7383                    cx,
 7384                );
 7385
 7386                // Find an insertion that starts at the cursor position.
 7387                let snapshot = self.buffer.read(cx).snapshot(cx);
 7388                let cursor_offset = self
 7389                    .selections
 7390                    .newest::<usize>(&self.display_snapshot(cx))
 7391                    .head();
 7392                let insertion = edits.iter().find_map(|(range, text)| {
 7393                    let range = range.to_offset(&snapshot);
 7394                    if range.is_empty() && range.start == cursor_offset {
 7395                        Some(text)
 7396                    } else {
 7397                        None
 7398                    }
 7399                });
 7400
 7401                if let Some(text) = insertion {
 7402                    let mut partial_completion = text
 7403                        .chars()
 7404                        .by_ref()
 7405                        .take_while(|c| c.is_alphabetic())
 7406                        .collect::<String>();
 7407                    if partial_completion.is_empty() {
 7408                        partial_completion = text
 7409                            .chars()
 7410                            .by_ref()
 7411                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7412                            .collect::<String>();
 7413                    }
 7414
 7415                    cx.emit(EditorEvent::InputHandled {
 7416                        utf16_range_to_replace: None,
 7417                        text: partial_completion.clone().into(),
 7418                    });
 7419
 7420                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7421
 7422                    self.refresh_edit_prediction(true, true, window, cx);
 7423                    cx.notify();
 7424                } else {
 7425                    self.accept_edit_prediction(&Default::default(), window, cx);
 7426                }
 7427            }
 7428        }
 7429    }
 7430
 7431    fn discard_edit_prediction(
 7432        &mut self,
 7433        should_report_edit_prediction_event: bool,
 7434        cx: &mut Context<Self>,
 7435    ) -> bool {
 7436        if should_report_edit_prediction_event {
 7437            let completion_id = self
 7438                .active_edit_prediction
 7439                .as_ref()
 7440                .and_then(|active_completion| active_completion.completion_id.clone());
 7441
 7442            self.report_edit_prediction_event(completion_id, false, cx);
 7443        }
 7444
 7445        if let Some(provider) = self.edit_prediction_provider() {
 7446            provider.discard(cx);
 7447        }
 7448
 7449        self.take_active_edit_prediction(cx)
 7450    }
 7451
 7452    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7453        let Some(provider) = self.edit_prediction_provider() else {
 7454            return;
 7455        };
 7456
 7457        let Some((_, buffer, _)) = self
 7458            .buffer
 7459            .read(cx)
 7460            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7461        else {
 7462            return;
 7463        };
 7464
 7465        let extension = buffer
 7466            .read(cx)
 7467            .file()
 7468            .and_then(|file| Some(file.path().extension()?.to_string()));
 7469
 7470        let event_type = match accepted {
 7471            true => "Edit Prediction Accepted",
 7472            false => "Edit Prediction Discarded",
 7473        };
 7474        telemetry::event!(
 7475            event_type,
 7476            provider = provider.name(),
 7477            prediction_id = id,
 7478            suggestion_accepted = accepted,
 7479            file_extension = extension,
 7480        );
 7481    }
 7482
 7483    fn open_editor_at_anchor(
 7484        snapshot: &language::BufferSnapshot,
 7485        target: language::Anchor,
 7486        workspace: &Entity<Workspace>,
 7487        window: &mut Window,
 7488        cx: &mut App,
 7489    ) -> Task<Result<()>> {
 7490        workspace.update(cx, |workspace, cx| {
 7491            let path = snapshot.file().map(|file| file.full_path(cx));
 7492            let Some(path) =
 7493                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7494            else {
 7495                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7496            };
 7497            let target = text::ToPoint::to_point(&target, snapshot);
 7498            let item = workspace.open_path(path, None, true, window, cx);
 7499            window.spawn(cx, async move |cx| {
 7500                let Some(editor) = item.await?.downcast::<Editor>() else {
 7501                    return Ok(());
 7502                };
 7503                editor
 7504                    .update_in(cx, |editor, window, cx| {
 7505                        editor.go_to_singleton_buffer_point(target, window, cx);
 7506                    })
 7507                    .ok();
 7508                anyhow::Ok(())
 7509            })
 7510        })
 7511    }
 7512
 7513    pub fn has_active_edit_prediction(&self) -> bool {
 7514        self.active_edit_prediction.is_some()
 7515    }
 7516
 7517    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7518        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7519            return false;
 7520        };
 7521
 7522        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7523        self.clear_highlights::<EditPredictionHighlight>(cx);
 7524        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7525        true
 7526    }
 7527
 7528    /// Returns true when we're displaying the edit prediction popover below the cursor
 7529    /// like we are not previewing and the LSP autocomplete menu is visible
 7530    /// or we are in `when_holding_modifier` mode.
 7531    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7532        if self.edit_prediction_preview_is_active()
 7533            || !self.show_edit_predictions_in_menu()
 7534            || !self.edit_predictions_enabled()
 7535        {
 7536            return false;
 7537        }
 7538
 7539        if self.has_visible_completions_menu() {
 7540            return true;
 7541        }
 7542
 7543        has_completion && self.edit_prediction_requires_modifier()
 7544    }
 7545
 7546    fn handle_modifiers_changed(
 7547        &mut self,
 7548        modifiers: Modifiers,
 7549        position_map: &PositionMap,
 7550        window: &mut Window,
 7551        cx: &mut Context<Self>,
 7552    ) {
 7553        if self.show_edit_predictions_in_menu() {
 7554            self.update_edit_prediction_preview(&modifiers, window, cx);
 7555        }
 7556
 7557        self.update_selection_mode(&modifiers, position_map, window, cx);
 7558
 7559        let mouse_position = window.mouse_position();
 7560        if !position_map.text_hitbox.is_hovered(window) {
 7561            return;
 7562        }
 7563
 7564        self.update_hovered_link(
 7565            position_map.point_for_position(mouse_position),
 7566            &position_map.snapshot,
 7567            modifiers,
 7568            window,
 7569            cx,
 7570        )
 7571    }
 7572
 7573    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7574        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7575        if invert {
 7576            match multi_cursor_setting {
 7577                MultiCursorModifier::Alt => modifiers.alt,
 7578                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7579            }
 7580        } else {
 7581            match multi_cursor_setting {
 7582                MultiCursorModifier::Alt => modifiers.secondary(),
 7583                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7584            }
 7585        }
 7586    }
 7587
 7588    fn columnar_selection_mode(
 7589        modifiers: &Modifiers,
 7590        cx: &mut Context<Self>,
 7591    ) -> Option<ColumnarMode> {
 7592        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7593            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7594                Some(ColumnarMode::FromMouse)
 7595            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7596                Some(ColumnarMode::FromSelection)
 7597            } else {
 7598                None
 7599            }
 7600        } else {
 7601            None
 7602        }
 7603    }
 7604
 7605    fn update_selection_mode(
 7606        &mut self,
 7607        modifiers: &Modifiers,
 7608        position_map: &PositionMap,
 7609        window: &mut Window,
 7610        cx: &mut Context<Self>,
 7611    ) {
 7612        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7613            return;
 7614        };
 7615        if self.selections.pending_anchor().is_none() {
 7616            return;
 7617        }
 7618
 7619        let mouse_position = window.mouse_position();
 7620        let point_for_position = position_map.point_for_position(mouse_position);
 7621        let position = point_for_position.previous_valid;
 7622
 7623        self.select(
 7624            SelectPhase::BeginColumnar {
 7625                position,
 7626                reset: false,
 7627                mode,
 7628                goal_column: point_for_position.exact_unclipped.column(),
 7629            },
 7630            window,
 7631            cx,
 7632        );
 7633    }
 7634
 7635    fn update_edit_prediction_preview(
 7636        &mut self,
 7637        modifiers: &Modifiers,
 7638        window: &mut Window,
 7639        cx: &mut Context<Self>,
 7640    ) {
 7641        let mut modifiers_held = false;
 7642        if let Some(accept_keystroke) = self
 7643            .accept_edit_prediction_keybind(false, window, cx)
 7644            .keystroke()
 7645        {
 7646            modifiers_held = modifiers_held
 7647                || (accept_keystroke.modifiers() == modifiers
 7648                    && accept_keystroke.modifiers().modified());
 7649        };
 7650        if let Some(accept_partial_keystroke) = self
 7651            .accept_edit_prediction_keybind(true, window, cx)
 7652            .keystroke()
 7653        {
 7654            modifiers_held = modifiers_held
 7655                || (accept_partial_keystroke.modifiers() == modifiers
 7656                    && accept_partial_keystroke.modifiers().modified());
 7657        }
 7658
 7659        if modifiers_held {
 7660            if matches!(
 7661                self.edit_prediction_preview,
 7662                EditPredictionPreview::Inactive { .. }
 7663            ) {
 7664                self.edit_prediction_preview = EditPredictionPreview::Active {
 7665                    previous_scroll_position: None,
 7666                    since: Instant::now(),
 7667                };
 7668
 7669                self.update_visible_edit_prediction(window, cx);
 7670                cx.notify();
 7671            }
 7672        } else if let EditPredictionPreview::Active {
 7673            previous_scroll_position,
 7674            since,
 7675        } = self.edit_prediction_preview
 7676        {
 7677            if let (Some(previous_scroll_position), Some(position_map)) =
 7678                (previous_scroll_position, self.last_position_map.as_ref())
 7679            {
 7680                self.set_scroll_position(
 7681                    previous_scroll_position
 7682                        .scroll_position(&position_map.snapshot.display_snapshot),
 7683                    window,
 7684                    cx,
 7685                );
 7686            }
 7687
 7688            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7689                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7690            };
 7691            self.clear_row_highlights::<EditPredictionPreview>();
 7692            self.update_visible_edit_prediction(window, cx);
 7693            cx.notify();
 7694        }
 7695    }
 7696
 7697    fn update_visible_edit_prediction(
 7698        &mut self,
 7699        _window: &mut Window,
 7700        cx: &mut Context<Self>,
 7701    ) -> Option<()> {
 7702        if DisableAiSettings::get_global(cx).disable_ai {
 7703            return None;
 7704        }
 7705
 7706        if self.ime_transaction.is_some() {
 7707            self.discard_edit_prediction(false, cx);
 7708            return None;
 7709        }
 7710
 7711        let selection = self.selections.newest_anchor();
 7712        let cursor = selection.head();
 7713        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7714        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7715        let excerpt_id = cursor.excerpt_id;
 7716
 7717        let show_in_menu = self.show_edit_predictions_in_menu();
 7718        let completions_menu_has_precedence = !show_in_menu
 7719            && (self.context_menu.borrow().is_some()
 7720                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7721
 7722        if completions_menu_has_precedence
 7723            || !offset_selection.is_empty()
 7724            || self
 7725                .active_edit_prediction
 7726                .as_ref()
 7727                .is_some_and(|completion| {
 7728                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7729                        return false;
 7730                    };
 7731                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7732                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7733                    !invalidation_range.contains(&offset_selection.head())
 7734                })
 7735        {
 7736            self.discard_edit_prediction(false, cx);
 7737            return None;
 7738        }
 7739
 7740        self.take_active_edit_prediction(cx);
 7741        let Some(provider) = self.edit_prediction_provider() else {
 7742            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7743            return None;
 7744        };
 7745
 7746        let (buffer, cursor_buffer_position) =
 7747            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7748
 7749        self.edit_prediction_settings =
 7750            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7751
 7752        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7753
 7754        if self.edit_prediction_indent_conflict {
 7755            let cursor_point = cursor.to_point(&multibuffer);
 7756
 7757            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7758
 7759            if let Some((_, indent)) = indents.iter().next()
 7760                && indent.len == cursor_point.column
 7761            {
 7762                self.edit_prediction_indent_conflict = false;
 7763            }
 7764        }
 7765
 7766        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7767
 7768        let (completion_id, edits, edit_preview) = match edit_prediction {
 7769            edit_prediction::EditPrediction::Local {
 7770                id,
 7771                edits,
 7772                edit_preview,
 7773            } => (id, edits, edit_preview),
 7774            edit_prediction::EditPrediction::Jump {
 7775                id,
 7776                snapshot,
 7777                target,
 7778            } => {
 7779                self.stale_edit_prediction_in_menu = None;
 7780                self.active_edit_prediction = Some(EditPredictionState {
 7781                    inlay_ids: vec![],
 7782                    completion: EditPrediction::MoveOutside { snapshot, target },
 7783                    completion_id: id,
 7784                    invalidation_range: None,
 7785                });
 7786                cx.notify();
 7787                return Some(());
 7788            }
 7789        };
 7790
 7791        let edits = edits
 7792            .into_iter()
 7793            .flat_map(|(range, new_text)| {
 7794                Some((
 7795                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7796                    new_text,
 7797                ))
 7798            })
 7799            .collect::<Vec<_>>();
 7800        if edits.is_empty() {
 7801            return None;
 7802        }
 7803
 7804        let first_edit_start = edits.first().unwrap().0.start;
 7805        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7806        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7807
 7808        let last_edit_end = edits.last().unwrap().0.end;
 7809        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7810        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7811
 7812        let cursor_row = cursor.to_point(&multibuffer).row;
 7813
 7814        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7815
 7816        let mut inlay_ids = Vec::new();
 7817        let invalidation_row_range;
 7818        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7819            Some(cursor_row..edit_end_row)
 7820        } else if cursor_row > edit_end_row {
 7821            Some(edit_start_row..cursor_row)
 7822        } else {
 7823            None
 7824        };
 7825        let supports_jump = self
 7826            .edit_prediction_provider
 7827            .as_ref()
 7828            .map(|provider| provider.provider.supports_jump_to_edit())
 7829            .unwrap_or(true);
 7830
 7831        let is_move = supports_jump
 7832            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7833        let completion = if is_move {
 7834            invalidation_row_range =
 7835                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7836            let target = first_edit_start;
 7837            EditPrediction::MoveWithin { target, snapshot }
 7838        } else {
 7839            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7840                && !self.edit_predictions_hidden_for_vim_mode;
 7841
 7842            if show_completions_in_buffer {
 7843                if edits
 7844                    .iter()
 7845                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7846                {
 7847                    let mut inlays = Vec::new();
 7848                    for (range, new_text) in &edits {
 7849                        let inlay = Inlay::edit_prediction(
 7850                            post_inc(&mut self.next_inlay_id),
 7851                            range.start,
 7852                            new_text.as_str(),
 7853                        );
 7854                        inlay_ids.push(inlay.id);
 7855                        inlays.push(inlay);
 7856                    }
 7857
 7858                    self.splice_inlays(&[], inlays, cx);
 7859                } else {
 7860                    let background_color = cx.theme().status().deleted_background;
 7861                    self.highlight_text::<EditPredictionHighlight>(
 7862                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7863                        HighlightStyle {
 7864                            background_color: Some(background_color),
 7865                            ..Default::default()
 7866                        },
 7867                        cx,
 7868                    );
 7869                }
 7870            }
 7871
 7872            invalidation_row_range = edit_start_row..edit_end_row;
 7873
 7874            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7875                if provider.show_tab_accept_marker() {
 7876                    EditDisplayMode::TabAccept
 7877                } else {
 7878                    EditDisplayMode::Inline
 7879                }
 7880            } else {
 7881                EditDisplayMode::DiffPopover
 7882            };
 7883
 7884            EditPrediction::Edit {
 7885                edits,
 7886                edit_preview,
 7887                display_mode,
 7888                snapshot,
 7889            }
 7890        };
 7891
 7892        let invalidation_range = multibuffer
 7893            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7894            ..multibuffer.anchor_after(Point::new(
 7895                invalidation_row_range.end,
 7896                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7897            ));
 7898
 7899        self.stale_edit_prediction_in_menu = None;
 7900        self.active_edit_prediction = Some(EditPredictionState {
 7901            inlay_ids,
 7902            completion,
 7903            completion_id,
 7904            invalidation_range: Some(invalidation_range),
 7905        });
 7906
 7907        cx.notify();
 7908
 7909        Some(())
 7910    }
 7911
 7912    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7913        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7914    }
 7915
 7916    fn clear_tasks(&mut self) {
 7917        self.tasks.clear()
 7918    }
 7919
 7920    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7921        if self.tasks.insert(key, value).is_some() {
 7922            // This case should hopefully be rare, but just in case...
 7923            log::error!(
 7924                "multiple different run targets found on a single line, only the last target will be rendered"
 7925            )
 7926        }
 7927    }
 7928
 7929    /// Get all display points of breakpoints that will be rendered within editor
 7930    ///
 7931    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7932    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7933    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7934    fn active_breakpoints(
 7935        &self,
 7936        range: Range<DisplayRow>,
 7937        window: &mut Window,
 7938        cx: &mut Context<Self>,
 7939    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7940        let mut breakpoint_display_points = HashMap::default();
 7941
 7942        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7943            return breakpoint_display_points;
 7944        };
 7945
 7946        let snapshot = self.snapshot(window, cx);
 7947
 7948        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 7949        let Some(project) = self.project() else {
 7950            return breakpoint_display_points;
 7951        };
 7952
 7953        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7954            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7955
 7956        for (buffer_snapshot, range, excerpt_id) in
 7957            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7958        {
 7959            let Some(buffer) = project
 7960                .read(cx)
 7961                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7962            else {
 7963                continue;
 7964            };
 7965            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7966                &buffer,
 7967                Some(
 7968                    buffer_snapshot.anchor_before(range.start)
 7969                        ..buffer_snapshot.anchor_after(range.end),
 7970                ),
 7971                buffer_snapshot,
 7972                cx,
 7973            );
 7974            for (breakpoint, state) in breakpoints {
 7975                let multi_buffer_anchor =
 7976                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7977                let position = multi_buffer_anchor
 7978                    .to_point(&multi_buffer_snapshot)
 7979                    .to_display_point(&snapshot);
 7980
 7981                breakpoint_display_points.insert(
 7982                    position.row(),
 7983                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7984                );
 7985            }
 7986        }
 7987
 7988        breakpoint_display_points
 7989    }
 7990
 7991    fn breakpoint_context_menu(
 7992        &self,
 7993        anchor: Anchor,
 7994        window: &mut Window,
 7995        cx: &mut Context<Self>,
 7996    ) -> Entity<ui::ContextMenu> {
 7997        let weak_editor = cx.weak_entity();
 7998        let focus_handle = self.focus_handle(cx);
 7999
 8000        let row = self
 8001            .buffer
 8002            .read(cx)
 8003            .snapshot(cx)
 8004            .summary_for_anchor::<Point>(&anchor)
 8005            .row;
 8006
 8007        let breakpoint = self
 8008            .breakpoint_at_row(row, window, cx)
 8009            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8010
 8011        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8012            "Edit Log Breakpoint"
 8013        } else {
 8014            "Set Log Breakpoint"
 8015        };
 8016
 8017        let condition_breakpoint_msg = if breakpoint
 8018            .as_ref()
 8019            .is_some_and(|bp| bp.1.condition.is_some())
 8020        {
 8021            "Edit Condition Breakpoint"
 8022        } else {
 8023            "Set Condition Breakpoint"
 8024        };
 8025
 8026        let hit_condition_breakpoint_msg = if breakpoint
 8027            .as_ref()
 8028            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8029        {
 8030            "Edit Hit Condition Breakpoint"
 8031        } else {
 8032            "Set Hit Condition Breakpoint"
 8033        };
 8034
 8035        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8036            "Unset Breakpoint"
 8037        } else {
 8038            "Set Breakpoint"
 8039        };
 8040
 8041        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8042
 8043        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8044            BreakpointState::Enabled => Some("Disable"),
 8045            BreakpointState::Disabled => Some("Enable"),
 8046        });
 8047
 8048        let (anchor, breakpoint) =
 8049            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8050
 8051        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8052            menu.on_blur_subscription(Subscription::new(|| {}))
 8053                .context(focus_handle)
 8054                .when(run_to_cursor, |this| {
 8055                    let weak_editor = weak_editor.clone();
 8056                    this.entry("Run to cursor", None, move |window, cx| {
 8057                        weak_editor
 8058                            .update(cx, |editor, cx| {
 8059                                editor.change_selections(
 8060                                    SelectionEffects::no_scroll(),
 8061                                    window,
 8062                                    cx,
 8063                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8064                                );
 8065                            })
 8066                            .ok();
 8067
 8068                        window.dispatch_action(Box::new(RunToCursor), cx);
 8069                    })
 8070                    .separator()
 8071                })
 8072                .when_some(toggle_state_msg, |this, msg| {
 8073                    this.entry(msg, None, {
 8074                        let weak_editor = weak_editor.clone();
 8075                        let breakpoint = breakpoint.clone();
 8076                        move |_window, cx| {
 8077                            weak_editor
 8078                                .update(cx, |this, cx| {
 8079                                    this.edit_breakpoint_at_anchor(
 8080                                        anchor,
 8081                                        breakpoint.as_ref().clone(),
 8082                                        BreakpointEditAction::InvertState,
 8083                                        cx,
 8084                                    );
 8085                                })
 8086                                .log_err();
 8087                        }
 8088                    })
 8089                })
 8090                .entry(set_breakpoint_msg, None, {
 8091                    let weak_editor = weak_editor.clone();
 8092                    let breakpoint = breakpoint.clone();
 8093                    move |_window, cx| {
 8094                        weak_editor
 8095                            .update(cx, |this, cx| {
 8096                                this.edit_breakpoint_at_anchor(
 8097                                    anchor,
 8098                                    breakpoint.as_ref().clone(),
 8099                                    BreakpointEditAction::Toggle,
 8100                                    cx,
 8101                                );
 8102                            })
 8103                            .log_err();
 8104                    }
 8105                })
 8106                .entry(log_breakpoint_msg, None, {
 8107                    let breakpoint = breakpoint.clone();
 8108                    let weak_editor = weak_editor.clone();
 8109                    move |window, cx| {
 8110                        weak_editor
 8111                            .update(cx, |this, cx| {
 8112                                this.add_edit_breakpoint_block(
 8113                                    anchor,
 8114                                    breakpoint.as_ref(),
 8115                                    BreakpointPromptEditAction::Log,
 8116                                    window,
 8117                                    cx,
 8118                                );
 8119                            })
 8120                            .log_err();
 8121                    }
 8122                })
 8123                .entry(condition_breakpoint_msg, None, {
 8124                    let breakpoint = breakpoint.clone();
 8125                    let weak_editor = weak_editor.clone();
 8126                    move |window, cx| {
 8127                        weak_editor
 8128                            .update(cx, |this, cx| {
 8129                                this.add_edit_breakpoint_block(
 8130                                    anchor,
 8131                                    breakpoint.as_ref(),
 8132                                    BreakpointPromptEditAction::Condition,
 8133                                    window,
 8134                                    cx,
 8135                                );
 8136                            })
 8137                            .log_err();
 8138                    }
 8139                })
 8140                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8141                    weak_editor
 8142                        .update(cx, |this, cx| {
 8143                            this.add_edit_breakpoint_block(
 8144                                anchor,
 8145                                breakpoint.as_ref(),
 8146                                BreakpointPromptEditAction::HitCondition,
 8147                                window,
 8148                                cx,
 8149                            );
 8150                        })
 8151                        .log_err();
 8152                })
 8153        })
 8154    }
 8155
 8156    fn render_breakpoint(
 8157        &self,
 8158        position: Anchor,
 8159        row: DisplayRow,
 8160        breakpoint: &Breakpoint,
 8161        state: Option<BreakpointSessionState>,
 8162        cx: &mut Context<Self>,
 8163    ) -> IconButton {
 8164        let is_rejected = state.is_some_and(|s| !s.verified);
 8165        // Is it a breakpoint that shows up when hovering over gutter?
 8166        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8167            (false, false),
 8168            |PhantomBreakpointIndicator {
 8169                 is_active,
 8170                 display_row,
 8171                 collides_with_existing_breakpoint,
 8172             }| {
 8173                (
 8174                    is_active && display_row == row,
 8175                    collides_with_existing_breakpoint,
 8176                )
 8177            },
 8178        );
 8179
 8180        let (color, icon) = {
 8181            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8182                (false, false) => ui::IconName::DebugBreakpoint,
 8183                (true, false) => ui::IconName::DebugLogBreakpoint,
 8184                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8185                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8186            };
 8187
 8188            let color = if is_phantom {
 8189                Color::Hint
 8190            } else if is_rejected {
 8191                Color::Disabled
 8192            } else {
 8193                Color::Debugger
 8194            };
 8195
 8196            (color, icon)
 8197        };
 8198
 8199        let breakpoint = Arc::from(breakpoint.clone());
 8200
 8201        let alt_as_text = gpui::Keystroke {
 8202            modifiers: Modifiers::secondary_key(),
 8203            ..Default::default()
 8204        };
 8205        let primary_action_text = if breakpoint.is_disabled() {
 8206            "Enable breakpoint"
 8207        } else if is_phantom && !collides_with_existing {
 8208            "Set breakpoint"
 8209        } else {
 8210            "Unset breakpoint"
 8211        };
 8212        let focus_handle = self.focus_handle.clone();
 8213
 8214        let meta = if is_rejected {
 8215            SharedString::from("No executable code is associated with this line.")
 8216        } else if collides_with_existing && !breakpoint.is_disabled() {
 8217            SharedString::from(format!(
 8218                "{alt_as_text}-click to disable,\nright-click for more options."
 8219            ))
 8220        } else {
 8221            SharedString::from("Right-click for more options.")
 8222        };
 8223        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8224            .icon_size(IconSize::XSmall)
 8225            .size(ui::ButtonSize::None)
 8226            .when(is_rejected, |this| {
 8227                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8228            })
 8229            .icon_color(color)
 8230            .style(ButtonStyle::Transparent)
 8231            .on_click(cx.listener({
 8232                move |editor, event: &ClickEvent, window, cx| {
 8233                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8234                        BreakpointEditAction::InvertState
 8235                    } else {
 8236                        BreakpointEditAction::Toggle
 8237                    };
 8238
 8239                    window.focus(&editor.focus_handle(cx));
 8240                    editor.edit_breakpoint_at_anchor(
 8241                        position,
 8242                        breakpoint.as_ref().clone(),
 8243                        edit_action,
 8244                        cx,
 8245                    );
 8246                }
 8247            }))
 8248            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8249                editor.set_breakpoint_context_menu(
 8250                    row,
 8251                    Some(position),
 8252                    event.position(),
 8253                    window,
 8254                    cx,
 8255                );
 8256            }))
 8257            .tooltip(move |_window, cx| {
 8258                Tooltip::with_meta_in(
 8259                    primary_action_text,
 8260                    Some(&ToggleBreakpoint),
 8261                    meta.clone(),
 8262                    &focus_handle,
 8263                    cx,
 8264                )
 8265            })
 8266    }
 8267
 8268    fn build_tasks_context(
 8269        project: &Entity<Project>,
 8270        buffer: &Entity<Buffer>,
 8271        buffer_row: u32,
 8272        tasks: &Arc<RunnableTasks>,
 8273        cx: &mut Context<Self>,
 8274    ) -> Task<Option<task::TaskContext>> {
 8275        let position = Point::new(buffer_row, tasks.column);
 8276        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8277        let location = Location {
 8278            buffer: buffer.clone(),
 8279            range: range_start..range_start,
 8280        };
 8281        // Fill in the environmental variables from the tree-sitter captures
 8282        let mut captured_task_variables = TaskVariables::default();
 8283        for (capture_name, value) in tasks.extra_variables.clone() {
 8284            captured_task_variables.insert(
 8285                task::VariableName::Custom(capture_name.into()),
 8286                value.clone(),
 8287            );
 8288        }
 8289        project.update(cx, |project, cx| {
 8290            project.task_store().update(cx, |task_store, cx| {
 8291                task_store.task_context_for_location(captured_task_variables, location, cx)
 8292            })
 8293        })
 8294    }
 8295
 8296    pub fn spawn_nearest_task(
 8297        &mut self,
 8298        action: &SpawnNearestTask,
 8299        window: &mut Window,
 8300        cx: &mut Context<Self>,
 8301    ) {
 8302        let Some((workspace, _)) = self.workspace.clone() else {
 8303            return;
 8304        };
 8305        let Some(project) = self.project.clone() else {
 8306            return;
 8307        };
 8308
 8309        // Try to find a closest, enclosing node using tree-sitter that has a task
 8310        let Some((buffer, buffer_row, tasks)) = self
 8311            .find_enclosing_node_task(cx)
 8312            // Or find the task that's closest in row-distance.
 8313            .or_else(|| self.find_closest_task(cx))
 8314        else {
 8315            return;
 8316        };
 8317
 8318        let reveal_strategy = action.reveal;
 8319        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8320        cx.spawn_in(window, async move |_, cx| {
 8321            let context = task_context.await?;
 8322            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8323
 8324            let resolved = &mut resolved_task.resolved;
 8325            resolved.reveal = reveal_strategy;
 8326
 8327            workspace
 8328                .update_in(cx, |workspace, window, cx| {
 8329                    workspace.schedule_resolved_task(
 8330                        task_source_kind,
 8331                        resolved_task,
 8332                        false,
 8333                        window,
 8334                        cx,
 8335                    );
 8336                })
 8337                .ok()
 8338        })
 8339        .detach();
 8340    }
 8341
 8342    fn find_closest_task(
 8343        &mut self,
 8344        cx: &mut Context<Self>,
 8345    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8346        let cursor_row = self
 8347            .selections
 8348            .newest_adjusted(&self.display_snapshot(cx))
 8349            .head()
 8350            .row;
 8351
 8352        let ((buffer_id, row), tasks) = self
 8353            .tasks
 8354            .iter()
 8355            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8356
 8357        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8358        let tasks = Arc::new(tasks.to_owned());
 8359        Some((buffer, *row, tasks))
 8360    }
 8361
 8362    fn find_enclosing_node_task(
 8363        &mut self,
 8364        cx: &mut Context<Self>,
 8365    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8366        let snapshot = self.buffer.read(cx).snapshot(cx);
 8367        let offset = self
 8368            .selections
 8369            .newest::<usize>(&self.display_snapshot(cx))
 8370            .head();
 8371        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8372        let buffer_id = excerpt.buffer().remote_id();
 8373
 8374        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8375        let mut cursor = layer.node().walk();
 8376
 8377        while cursor.goto_first_child_for_byte(offset).is_some() {
 8378            if cursor.node().end_byte() == offset {
 8379                cursor.goto_next_sibling();
 8380            }
 8381        }
 8382
 8383        // Ascend to the smallest ancestor that contains the range and has a task.
 8384        loop {
 8385            let node = cursor.node();
 8386            let node_range = node.byte_range();
 8387            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8388
 8389            // Check if this node contains our offset
 8390            if node_range.start <= offset && node_range.end >= offset {
 8391                // If it contains offset, check for task
 8392                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8393                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8394                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8395                }
 8396            }
 8397
 8398            if !cursor.goto_parent() {
 8399                break;
 8400            }
 8401        }
 8402        None
 8403    }
 8404
 8405    fn render_run_indicator(
 8406        &self,
 8407        _style: &EditorStyle,
 8408        is_active: bool,
 8409        row: DisplayRow,
 8410        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8411        cx: &mut Context<Self>,
 8412    ) -> IconButton {
 8413        let color = Color::Muted;
 8414        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8415
 8416        IconButton::new(
 8417            ("run_indicator", row.0 as usize),
 8418            ui::IconName::PlayOutlined,
 8419        )
 8420        .shape(ui::IconButtonShape::Square)
 8421        .icon_size(IconSize::XSmall)
 8422        .icon_color(color)
 8423        .toggle_state(is_active)
 8424        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8425            let quick_launch = match e {
 8426                ClickEvent::Keyboard(_) => true,
 8427                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8428            };
 8429
 8430            window.focus(&editor.focus_handle(cx));
 8431            editor.toggle_code_actions(
 8432                &ToggleCodeActions {
 8433                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8434                    quick_launch,
 8435                },
 8436                window,
 8437                cx,
 8438            );
 8439        }))
 8440        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8441            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8442        }))
 8443    }
 8444
 8445    pub fn context_menu_visible(&self) -> bool {
 8446        !self.edit_prediction_preview_is_active()
 8447            && self
 8448                .context_menu
 8449                .borrow()
 8450                .as_ref()
 8451                .is_some_and(|menu| menu.visible())
 8452    }
 8453
 8454    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8455        self.context_menu
 8456            .borrow()
 8457            .as_ref()
 8458            .map(|menu| menu.origin())
 8459    }
 8460
 8461    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8462        self.context_menu_options = Some(options);
 8463    }
 8464
 8465    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8466    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8467
 8468    fn render_edit_prediction_popover(
 8469        &mut self,
 8470        text_bounds: &Bounds<Pixels>,
 8471        content_origin: gpui::Point<Pixels>,
 8472        right_margin: Pixels,
 8473        editor_snapshot: &EditorSnapshot,
 8474        visible_row_range: Range<DisplayRow>,
 8475        scroll_top: ScrollOffset,
 8476        scroll_bottom: ScrollOffset,
 8477        line_layouts: &[LineWithInvisibles],
 8478        line_height: Pixels,
 8479        scroll_position: gpui::Point<ScrollOffset>,
 8480        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8481        newest_selection_head: Option<DisplayPoint>,
 8482        editor_width: Pixels,
 8483        style: &EditorStyle,
 8484        window: &mut Window,
 8485        cx: &mut App,
 8486    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8487        if self.mode().is_minimap() {
 8488            return None;
 8489        }
 8490        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8491
 8492        if self.edit_prediction_visible_in_cursor_popover(true) {
 8493            return None;
 8494        }
 8495
 8496        match &active_edit_prediction.completion {
 8497            EditPrediction::MoveWithin { target, .. } => {
 8498                let target_display_point = target.to_display_point(editor_snapshot);
 8499
 8500                if self.edit_prediction_requires_modifier() {
 8501                    if !self.edit_prediction_preview_is_active() {
 8502                        return None;
 8503                    }
 8504
 8505                    self.render_edit_prediction_modifier_jump_popover(
 8506                        text_bounds,
 8507                        content_origin,
 8508                        visible_row_range,
 8509                        line_layouts,
 8510                        line_height,
 8511                        scroll_pixel_position,
 8512                        newest_selection_head,
 8513                        target_display_point,
 8514                        window,
 8515                        cx,
 8516                    )
 8517                } else {
 8518                    self.render_edit_prediction_eager_jump_popover(
 8519                        text_bounds,
 8520                        content_origin,
 8521                        editor_snapshot,
 8522                        visible_row_range,
 8523                        scroll_top,
 8524                        scroll_bottom,
 8525                        line_height,
 8526                        scroll_pixel_position,
 8527                        target_display_point,
 8528                        editor_width,
 8529                        window,
 8530                        cx,
 8531                    )
 8532                }
 8533            }
 8534            EditPrediction::Edit {
 8535                display_mode: EditDisplayMode::Inline,
 8536                ..
 8537            } => None,
 8538            EditPrediction::Edit {
 8539                display_mode: EditDisplayMode::TabAccept,
 8540                edits,
 8541                ..
 8542            } => {
 8543                let range = &edits.first()?.0;
 8544                let target_display_point = range.end.to_display_point(editor_snapshot);
 8545
 8546                self.render_edit_prediction_end_of_line_popover(
 8547                    "Accept",
 8548                    editor_snapshot,
 8549                    visible_row_range,
 8550                    target_display_point,
 8551                    line_height,
 8552                    scroll_pixel_position,
 8553                    content_origin,
 8554                    editor_width,
 8555                    window,
 8556                    cx,
 8557                )
 8558            }
 8559            EditPrediction::Edit {
 8560                edits,
 8561                edit_preview,
 8562                display_mode: EditDisplayMode::DiffPopover,
 8563                snapshot,
 8564            } => self.render_edit_prediction_diff_popover(
 8565                text_bounds,
 8566                content_origin,
 8567                right_margin,
 8568                editor_snapshot,
 8569                visible_row_range,
 8570                line_layouts,
 8571                line_height,
 8572                scroll_position,
 8573                scroll_pixel_position,
 8574                newest_selection_head,
 8575                editor_width,
 8576                style,
 8577                edits,
 8578                edit_preview,
 8579                snapshot,
 8580                window,
 8581                cx,
 8582            ),
 8583            EditPrediction::MoveOutside { snapshot, .. } => {
 8584                let file_name = snapshot
 8585                    .file()
 8586                    .map(|file| file.file_name(cx))
 8587                    .unwrap_or("untitled");
 8588                let mut element = self
 8589                    .render_edit_prediction_line_popover(
 8590                        format!("Jump to {file_name}"),
 8591                        Some(IconName::ZedPredict),
 8592                        window,
 8593                        cx,
 8594                    )
 8595                    .into_any();
 8596
 8597                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8598                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8599                let origin_y = text_bounds.size.height - size.height - px(30.);
 8600                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8601                element.prepaint_at(origin, window, cx);
 8602
 8603                Some((element, origin))
 8604            }
 8605        }
 8606    }
 8607
 8608    fn render_edit_prediction_modifier_jump_popover(
 8609        &mut self,
 8610        text_bounds: &Bounds<Pixels>,
 8611        content_origin: gpui::Point<Pixels>,
 8612        visible_row_range: Range<DisplayRow>,
 8613        line_layouts: &[LineWithInvisibles],
 8614        line_height: Pixels,
 8615        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8616        newest_selection_head: Option<DisplayPoint>,
 8617        target_display_point: DisplayPoint,
 8618        window: &mut Window,
 8619        cx: &mut App,
 8620    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8621        let scrolled_content_origin =
 8622            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8623
 8624        const SCROLL_PADDING_Y: Pixels = px(12.);
 8625
 8626        if target_display_point.row() < visible_row_range.start {
 8627            return self.render_edit_prediction_scroll_popover(
 8628                |_| SCROLL_PADDING_Y,
 8629                IconName::ArrowUp,
 8630                visible_row_range,
 8631                line_layouts,
 8632                newest_selection_head,
 8633                scrolled_content_origin,
 8634                window,
 8635                cx,
 8636            );
 8637        } else if target_display_point.row() >= visible_row_range.end {
 8638            return self.render_edit_prediction_scroll_popover(
 8639                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8640                IconName::ArrowDown,
 8641                visible_row_range,
 8642                line_layouts,
 8643                newest_selection_head,
 8644                scrolled_content_origin,
 8645                window,
 8646                cx,
 8647            );
 8648        }
 8649
 8650        const POLE_WIDTH: Pixels = px(2.);
 8651
 8652        let line_layout =
 8653            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8654        let target_column = target_display_point.column() as usize;
 8655
 8656        let target_x = line_layout.x_for_index(target_column);
 8657        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8658            - scroll_pixel_position.y;
 8659
 8660        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8661
 8662        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8663        border_color.l += 0.001;
 8664
 8665        let mut element = v_flex()
 8666            .items_end()
 8667            .when(flag_on_right, |el| el.items_start())
 8668            .child(if flag_on_right {
 8669                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8670                    .rounded_bl(px(0.))
 8671                    .rounded_tl(px(0.))
 8672                    .border_l_2()
 8673                    .border_color(border_color)
 8674            } else {
 8675                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8676                    .rounded_br(px(0.))
 8677                    .rounded_tr(px(0.))
 8678                    .border_r_2()
 8679                    .border_color(border_color)
 8680            })
 8681            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8682            .into_any();
 8683
 8684        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8685
 8686        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8687            - point(
 8688                if flag_on_right {
 8689                    POLE_WIDTH
 8690                } else {
 8691                    size.width - POLE_WIDTH
 8692                },
 8693                size.height - line_height,
 8694            );
 8695
 8696        origin.x = origin.x.max(content_origin.x);
 8697
 8698        element.prepaint_at(origin, window, cx);
 8699
 8700        Some((element, origin))
 8701    }
 8702
 8703    fn render_edit_prediction_scroll_popover(
 8704        &mut self,
 8705        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8706        scroll_icon: IconName,
 8707        visible_row_range: Range<DisplayRow>,
 8708        line_layouts: &[LineWithInvisibles],
 8709        newest_selection_head: Option<DisplayPoint>,
 8710        scrolled_content_origin: gpui::Point<Pixels>,
 8711        window: &mut Window,
 8712        cx: &mut App,
 8713    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8714        let mut element = self
 8715            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8716            .into_any();
 8717
 8718        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8719
 8720        let cursor = newest_selection_head?;
 8721        let cursor_row_layout =
 8722            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8723        let cursor_column = cursor.column() as usize;
 8724
 8725        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8726
 8727        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8728
 8729        element.prepaint_at(origin, window, cx);
 8730        Some((element, origin))
 8731    }
 8732
 8733    fn render_edit_prediction_eager_jump_popover(
 8734        &mut self,
 8735        text_bounds: &Bounds<Pixels>,
 8736        content_origin: gpui::Point<Pixels>,
 8737        editor_snapshot: &EditorSnapshot,
 8738        visible_row_range: Range<DisplayRow>,
 8739        scroll_top: ScrollOffset,
 8740        scroll_bottom: ScrollOffset,
 8741        line_height: Pixels,
 8742        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8743        target_display_point: DisplayPoint,
 8744        editor_width: Pixels,
 8745        window: &mut Window,
 8746        cx: &mut App,
 8747    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8748        if target_display_point.row().as_f64() < scroll_top {
 8749            let mut element = self
 8750                .render_edit_prediction_line_popover(
 8751                    "Jump to Edit",
 8752                    Some(IconName::ArrowUp),
 8753                    window,
 8754                    cx,
 8755                )
 8756                .into_any();
 8757
 8758            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8759            let offset = point(
 8760                (text_bounds.size.width - size.width) / 2.,
 8761                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8762            );
 8763
 8764            let origin = text_bounds.origin + offset;
 8765            element.prepaint_at(origin, window, cx);
 8766            Some((element, origin))
 8767        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8768            let mut element = self
 8769                .render_edit_prediction_line_popover(
 8770                    "Jump to Edit",
 8771                    Some(IconName::ArrowDown),
 8772                    window,
 8773                    cx,
 8774                )
 8775                .into_any();
 8776
 8777            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8778            let offset = point(
 8779                (text_bounds.size.width - size.width) / 2.,
 8780                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8781            );
 8782
 8783            let origin = text_bounds.origin + offset;
 8784            element.prepaint_at(origin, window, cx);
 8785            Some((element, origin))
 8786        } else {
 8787            self.render_edit_prediction_end_of_line_popover(
 8788                "Jump to Edit",
 8789                editor_snapshot,
 8790                visible_row_range,
 8791                target_display_point,
 8792                line_height,
 8793                scroll_pixel_position,
 8794                content_origin,
 8795                editor_width,
 8796                window,
 8797                cx,
 8798            )
 8799        }
 8800    }
 8801
 8802    fn render_edit_prediction_end_of_line_popover(
 8803        self: &mut Editor,
 8804        label: &'static str,
 8805        editor_snapshot: &EditorSnapshot,
 8806        visible_row_range: Range<DisplayRow>,
 8807        target_display_point: DisplayPoint,
 8808        line_height: Pixels,
 8809        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8810        content_origin: gpui::Point<Pixels>,
 8811        editor_width: Pixels,
 8812        window: &mut Window,
 8813        cx: &mut App,
 8814    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8815        let target_line_end = DisplayPoint::new(
 8816            target_display_point.row(),
 8817            editor_snapshot.line_len(target_display_point.row()),
 8818        );
 8819
 8820        let mut element = self
 8821            .render_edit_prediction_line_popover(label, None, window, cx)
 8822            .into_any();
 8823
 8824        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8825
 8826        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8827
 8828        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8829        let mut origin = start_point
 8830            + line_origin
 8831            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8832        origin.x = origin.x.max(content_origin.x);
 8833
 8834        let max_x = content_origin.x + editor_width - size.width;
 8835
 8836        if origin.x > max_x {
 8837            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8838
 8839            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8840                origin.y += offset;
 8841                IconName::ArrowUp
 8842            } else {
 8843                origin.y -= offset;
 8844                IconName::ArrowDown
 8845            };
 8846
 8847            element = self
 8848                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8849                .into_any();
 8850
 8851            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8852
 8853            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8854        }
 8855
 8856        element.prepaint_at(origin, window, cx);
 8857        Some((element, origin))
 8858    }
 8859
 8860    fn render_edit_prediction_diff_popover(
 8861        self: &Editor,
 8862        text_bounds: &Bounds<Pixels>,
 8863        content_origin: gpui::Point<Pixels>,
 8864        right_margin: Pixels,
 8865        editor_snapshot: &EditorSnapshot,
 8866        visible_row_range: Range<DisplayRow>,
 8867        line_layouts: &[LineWithInvisibles],
 8868        line_height: Pixels,
 8869        scroll_position: gpui::Point<ScrollOffset>,
 8870        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8871        newest_selection_head: Option<DisplayPoint>,
 8872        editor_width: Pixels,
 8873        style: &EditorStyle,
 8874        edits: &Vec<(Range<Anchor>, String)>,
 8875        edit_preview: &Option<language::EditPreview>,
 8876        snapshot: &language::BufferSnapshot,
 8877        window: &mut Window,
 8878        cx: &mut App,
 8879    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8880        let edit_start = edits
 8881            .first()
 8882            .unwrap()
 8883            .0
 8884            .start
 8885            .to_display_point(editor_snapshot);
 8886        let edit_end = edits
 8887            .last()
 8888            .unwrap()
 8889            .0
 8890            .end
 8891            .to_display_point(editor_snapshot);
 8892
 8893        let is_visible = visible_row_range.contains(&edit_start.row())
 8894            || visible_row_range.contains(&edit_end.row());
 8895        if !is_visible {
 8896            return None;
 8897        }
 8898
 8899        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8900            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8901        } else {
 8902            // Fallback for providers without edit_preview
 8903            crate::edit_prediction_fallback_text(edits, cx)
 8904        };
 8905
 8906        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8907        let line_count = highlighted_edits.text.lines().count();
 8908
 8909        const BORDER_WIDTH: Pixels = px(1.);
 8910
 8911        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8912        let has_keybind = keybind.is_some();
 8913
 8914        let mut element = h_flex()
 8915            .items_start()
 8916            .child(
 8917                h_flex()
 8918                    .bg(cx.theme().colors().editor_background)
 8919                    .border(BORDER_WIDTH)
 8920                    .shadow_xs()
 8921                    .border_color(cx.theme().colors().border)
 8922                    .rounded_l_lg()
 8923                    .when(line_count > 1, |el| el.rounded_br_lg())
 8924                    .pr_1()
 8925                    .child(styled_text),
 8926            )
 8927            .child(
 8928                h_flex()
 8929                    .h(line_height + BORDER_WIDTH * 2.)
 8930                    .px_1p5()
 8931                    .gap_1()
 8932                    // Workaround: For some reason, there's a gap if we don't do this
 8933                    .ml(-BORDER_WIDTH)
 8934                    .shadow(vec![gpui::BoxShadow {
 8935                        color: gpui::black().opacity(0.05),
 8936                        offset: point(px(1.), px(1.)),
 8937                        blur_radius: px(2.),
 8938                        spread_radius: px(0.),
 8939                    }])
 8940                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8941                    .border(BORDER_WIDTH)
 8942                    .border_color(cx.theme().colors().border)
 8943                    .rounded_r_lg()
 8944                    .id("edit_prediction_diff_popover_keybind")
 8945                    .when(!has_keybind, |el| {
 8946                        let status_colors = cx.theme().status();
 8947
 8948                        el.bg(status_colors.error_background)
 8949                            .border_color(status_colors.error.opacity(0.6))
 8950                            .child(Icon::new(IconName::Info).color(Color::Error))
 8951                            .cursor_default()
 8952                            .hoverable_tooltip(move |_window, cx| {
 8953                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8954                            })
 8955                    })
 8956                    .children(keybind),
 8957            )
 8958            .into_any();
 8959
 8960        let longest_row =
 8961            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8962        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8963            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8964        } else {
 8965            layout_line(
 8966                longest_row,
 8967                editor_snapshot,
 8968                style,
 8969                editor_width,
 8970                |_| false,
 8971                window,
 8972                cx,
 8973            )
 8974            .width
 8975        };
 8976
 8977        let viewport_bounds =
 8978            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8979                right: -right_margin,
 8980                ..Default::default()
 8981            });
 8982
 8983        let x_after_longest = Pixels::from(
 8984            ScrollPixelOffset::from(
 8985                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 8986            ) - scroll_pixel_position.x,
 8987        );
 8988
 8989        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8990
 8991        // Fully visible if it can be displayed within the window (allow overlapping other
 8992        // panes). However, this is only allowed if the popover starts within text_bounds.
 8993        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8994            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8995
 8996        let mut origin = if can_position_to_the_right {
 8997            point(
 8998                x_after_longest,
 8999                text_bounds.origin.y
 9000                    + Pixels::from(
 9001                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9002                            - scroll_pixel_position.y,
 9003                    ),
 9004            )
 9005        } else {
 9006            let cursor_row = newest_selection_head.map(|head| head.row());
 9007            let above_edit = edit_start
 9008                .row()
 9009                .0
 9010                .checked_sub(line_count as u32)
 9011                .map(DisplayRow);
 9012            let below_edit = Some(edit_end.row() + 1);
 9013            let above_cursor =
 9014                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9015            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9016
 9017            // Place the edit popover adjacent to the edit if there is a location
 9018            // available that is onscreen and does not obscure the cursor. Otherwise,
 9019            // place it adjacent to the cursor.
 9020            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9021                .into_iter()
 9022                .flatten()
 9023                .find(|&start_row| {
 9024                    let end_row = start_row + line_count as u32;
 9025                    visible_row_range.contains(&start_row)
 9026                        && visible_row_range.contains(&end_row)
 9027                        && cursor_row
 9028                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9029                })?;
 9030
 9031            content_origin
 9032                + point(
 9033                    Pixels::from(-scroll_pixel_position.x),
 9034                    Pixels::from(
 9035                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9036                    ),
 9037                )
 9038        };
 9039
 9040        origin.x -= BORDER_WIDTH;
 9041
 9042        window.defer_draw(element, origin, 1);
 9043
 9044        // Do not return an element, since it will already be drawn due to defer_draw.
 9045        None
 9046    }
 9047
 9048    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9049        px(30.)
 9050    }
 9051
 9052    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9053        if self.read_only(cx) {
 9054            cx.theme().players().read_only()
 9055        } else {
 9056            self.style.as_ref().unwrap().local_player
 9057        }
 9058    }
 9059
 9060    fn render_edit_prediction_accept_keybind(
 9061        &self,
 9062        window: &mut Window,
 9063        cx: &mut App,
 9064    ) -> Option<AnyElement> {
 9065        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9066        let accept_keystroke = accept_binding.keystroke()?;
 9067
 9068        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9069
 9070        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9071            Color::Accent
 9072        } else {
 9073            Color::Muted
 9074        };
 9075
 9076        h_flex()
 9077            .px_0p5()
 9078            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9079            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9080            .text_size(TextSize::XSmall.rems(cx))
 9081            .child(h_flex().children(ui::render_modifiers(
 9082                accept_keystroke.modifiers(),
 9083                PlatformStyle::platform(),
 9084                Some(modifiers_color),
 9085                Some(IconSize::XSmall.rems().into()),
 9086                true,
 9087            )))
 9088            .when(is_platform_style_mac, |parent| {
 9089                parent.child(accept_keystroke.key().to_string())
 9090            })
 9091            .when(!is_platform_style_mac, |parent| {
 9092                parent.child(
 9093                    Key::new(
 9094                        util::capitalize(accept_keystroke.key()),
 9095                        Some(Color::Default),
 9096                    )
 9097                    .size(Some(IconSize::XSmall.rems().into())),
 9098                )
 9099            })
 9100            .into_any()
 9101            .into()
 9102    }
 9103
 9104    fn render_edit_prediction_line_popover(
 9105        &self,
 9106        label: impl Into<SharedString>,
 9107        icon: Option<IconName>,
 9108        window: &mut Window,
 9109        cx: &mut App,
 9110    ) -> Stateful<Div> {
 9111        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9112
 9113        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9114        let has_keybind = keybind.is_some();
 9115
 9116        h_flex()
 9117            .id("ep-line-popover")
 9118            .py_0p5()
 9119            .pl_1()
 9120            .pr(padding_right)
 9121            .gap_1()
 9122            .rounded_md()
 9123            .border_1()
 9124            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9125            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9126            .shadow_xs()
 9127            .when(!has_keybind, |el| {
 9128                let status_colors = cx.theme().status();
 9129
 9130                el.bg(status_colors.error_background)
 9131                    .border_color(status_colors.error.opacity(0.6))
 9132                    .pl_2()
 9133                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9134                    .cursor_default()
 9135                    .hoverable_tooltip(move |_window, cx| {
 9136                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9137                    })
 9138            })
 9139            .children(keybind)
 9140            .child(
 9141                Label::new(label)
 9142                    .size(LabelSize::Small)
 9143                    .when(!has_keybind, |el| {
 9144                        el.color(cx.theme().status().error.into()).strikethrough()
 9145                    }),
 9146            )
 9147            .when(!has_keybind, |el| {
 9148                el.child(
 9149                    h_flex().ml_1().child(
 9150                        Icon::new(IconName::Info)
 9151                            .size(IconSize::Small)
 9152                            .color(cx.theme().status().error.into()),
 9153                    ),
 9154                )
 9155            })
 9156            .when_some(icon, |element, icon| {
 9157                element.child(
 9158                    div()
 9159                        .mt(px(1.5))
 9160                        .child(Icon::new(icon).size(IconSize::Small)),
 9161                )
 9162            })
 9163    }
 9164
 9165    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9166        let accent_color = cx.theme().colors().text_accent;
 9167        let editor_bg_color = cx.theme().colors().editor_background;
 9168        editor_bg_color.blend(accent_color.opacity(0.1))
 9169    }
 9170
 9171    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9172        let accent_color = cx.theme().colors().text_accent;
 9173        let editor_bg_color = cx.theme().colors().editor_background;
 9174        editor_bg_color.blend(accent_color.opacity(0.6))
 9175    }
 9176    fn get_prediction_provider_icon_name(
 9177        provider: &Option<RegisteredEditPredictionProvider>,
 9178    ) -> IconName {
 9179        match provider {
 9180            Some(provider) => match provider.provider.name() {
 9181                "copilot" => IconName::Copilot,
 9182                "supermaven" => IconName::Supermaven,
 9183                _ => IconName::ZedPredict,
 9184            },
 9185            None => IconName::ZedPredict,
 9186        }
 9187    }
 9188
 9189    fn render_edit_prediction_cursor_popover(
 9190        &self,
 9191        min_width: Pixels,
 9192        max_width: Pixels,
 9193        cursor_point: Point,
 9194        style: &EditorStyle,
 9195        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9196        _window: &Window,
 9197        cx: &mut Context<Editor>,
 9198    ) -> Option<AnyElement> {
 9199        let provider = self.edit_prediction_provider.as_ref()?;
 9200        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9201
 9202        let is_refreshing = provider.provider.is_refreshing(cx);
 9203
 9204        fn pending_completion_container(icon: IconName) -> Div {
 9205            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9206        }
 9207
 9208        let completion = match &self.active_edit_prediction {
 9209            Some(prediction) => {
 9210                if !self.has_visible_completions_menu() {
 9211                    const RADIUS: Pixels = px(6.);
 9212                    const BORDER_WIDTH: Pixels = px(1.);
 9213
 9214                    return Some(
 9215                        h_flex()
 9216                            .elevation_2(cx)
 9217                            .border(BORDER_WIDTH)
 9218                            .border_color(cx.theme().colors().border)
 9219                            .when(accept_keystroke.is_none(), |el| {
 9220                                el.border_color(cx.theme().status().error)
 9221                            })
 9222                            .rounded(RADIUS)
 9223                            .rounded_tl(px(0.))
 9224                            .overflow_hidden()
 9225                            .child(div().px_1p5().child(match &prediction.completion {
 9226                                EditPrediction::MoveWithin { target, snapshot } => {
 9227                                    use text::ToPoint as _;
 9228                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9229                                    {
 9230                                        Icon::new(IconName::ZedPredictDown)
 9231                                    } else {
 9232                                        Icon::new(IconName::ZedPredictUp)
 9233                                    }
 9234                                }
 9235                                EditPrediction::MoveOutside { .. } => {
 9236                                    // TODO [zeta2] custom icon for external jump?
 9237                                    Icon::new(provider_icon)
 9238                                }
 9239                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9240                            }))
 9241                            .child(
 9242                                h_flex()
 9243                                    .gap_1()
 9244                                    .py_1()
 9245                                    .px_2()
 9246                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9247                                    .border_l_1()
 9248                                    .border_color(cx.theme().colors().border)
 9249                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9250                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9251                                        el.child(
 9252                                            Label::new("Hold")
 9253                                                .size(LabelSize::Small)
 9254                                                .when(accept_keystroke.is_none(), |el| {
 9255                                                    el.strikethrough()
 9256                                                })
 9257                                                .line_height_style(LineHeightStyle::UiLabel),
 9258                                        )
 9259                                    })
 9260                                    .id("edit_prediction_cursor_popover_keybind")
 9261                                    .when(accept_keystroke.is_none(), |el| {
 9262                                        let status_colors = cx.theme().status();
 9263
 9264                                        el.bg(status_colors.error_background)
 9265                                            .border_color(status_colors.error.opacity(0.6))
 9266                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9267                                            .cursor_default()
 9268                                            .hoverable_tooltip(move |_window, cx| {
 9269                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9270                                                    .into()
 9271                                            })
 9272                                    })
 9273                                    .when_some(
 9274                                        accept_keystroke.as_ref(),
 9275                                        |el, accept_keystroke| {
 9276                                            el.child(h_flex().children(ui::render_modifiers(
 9277                                                accept_keystroke.modifiers(),
 9278                                                PlatformStyle::platform(),
 9279                                                Some(Color::Default),
 9280                                                Some(IconSize::XSmall.rems().into()),
 9281                                                false,
 9282                                            )))
 9283                                        },
 9284                                    ),
 9285                            )
 9286                            .into_any(),
 9287                    );
 9288                }
 9289
 9290                self.render_edit_prediction_cursor_popover_preview(
 9291                    prediction,
 9292                    cursor_point,
 9293                    style,
 9294                    cx,
 9295                )?
 9296            }
 9297
 9298            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9299                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9300                    stale_completion,
 9301                    cursor_point,
 9302                    style,
 9303                    cx,
 9304                )?,
 9305
 9306                None => pending_completion_container(provider_icon)
 9307                    .child(Label::new("...").size(LabelSize::Small)),
 9308            },
 9309
 9310            None => pending_completion_container(provider_icon)
 9311                .child(Label::new("...").size(LabelSize::Small)),
 9312        };
 9313
 9314        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9315            completion
 9316                .with_animation(
 9317                    "loading-completion",
 9318                    Animation::new(Duration::from_secs(2))
 9319                        .repeat()
 9320                        .with_easing(pulsating_between(0.4, 0.8)),
 9321                    |label, delta| label.opacity(delta),
 9322                )
 9323                .into_any_element()
 9324        } else {
 9325            completion.into_any_element()
 9326        };
 9327
 9328        let has_completion = self.active_edit_prediction.is_some();
 9329
 9330        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9331        Some(
 9332            h_flex()
 9333                .min_w(min_width)
 9334                .max_w(max_width)
 9335                .flex_1()
 9336                .elevation_2(cx)
 9337                .border_color(cx.theme().colors().border)
 9338                .child(
 9339                    div()
 9340                        .flex_1()
 9341                        .py_1()
 9342                        .px_2()
 9343                        .overflow_hidden()
 9344                        .child(completion),
 9345                )
 9346                .when_some(accept_keystroke, |el, accept_keystroke| {
 9347                    if !accept_keystroke.modifiers().modified() {
 9348                        return el;
 9349                    }
 9350
 9351                    el.child(
 9352                        h_flex()
 9353                            .h_full()
 9354                            .border_l_1()
 9355                            .rounded_r_lg()
 9356                            .border_color(cx.theme().colors().border)
 9357                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9358                            .gap_1()
 9359                            .py_1()
 9360                            .px_2()
 9361                            .child(
 9362                                h_flex()
 9363                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9364                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9365                                    .child(h_flex().children(ui::render_modifiers(
 9366                                        accept_keystroke.modifiers(),
 9367                                        PlatformStyle::platform(),
 9368                                        Some(if !has_completion {
 9369                                            Color::Muted
 9370                                        } else {
 9371                                            Color::Default
 9372                                        }),
 9373                                        None,
 9374                                        false,
 9375                                    ))),
 9376                            )
 9377                            .child(Label::new("Preview").into_any_element())
 9378                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9379                    )
 9380                })
 9381                .into_any(),
 9382        )
 9383    }
 9384
 9385    fn render_edit_prediction_cursor_popover_preview(
 9386        &self,
 9387        completion: &EditPredictionState,
 9388        cursor_point: Point,
 9389        style: &EditorStyle,
 9390        cx: &mut Context<Editor>,
 9391    ) -> Option<Div> {
 9392        use text::ToPoint as _;
 9393
 9394        fn render_relative_row_jump(
 9395            prefix: impl Into<String>,
 9396            current_row: u32,
 9397            target_row: u32,
 9398        ) -> Div {
 9399            let (row_diff, arrow) = if target_row < current_row {
 9400                (current_row - target_row, IconName::ArrowUp)
 9401            } else {
 9402                (target_row - current_row, IconName::ArrowDown)
 9403            };
 9404
 9405            h_flex()
 9406                .child(
 9407                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9408                        .color(Color::Muted)
 9409                        .size(LabelSize::Small),
 9410                )
 9411                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9412        }
 9413
 9414        let supports_jump = self
 9415            .edit_prediction_provider
 9416            .as_ref()
 9417            .map(|provider| provider.provider.supports_jump_to_edit())
 9418            .unwrap_or(true);
 9419
 9420        match &completion.completion {
 9421            EditPrediction::MoveWithin {
 9422                target, snapshot, ..
 9423            } => {
 9424                if !supports_jump {
 9425                    return None;
 9426                }
 9427
 9428                Some(
 9429                    h_flex()
 9430                        .px_2()
 9431                        .gap_2()
 9432                        .flex_1()
 9433                        .child(
 9434                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9435                                Icon::new(IconName::ZedPredictDown)
 9436                            } else {
 9437                                Icon::new(IconName::ZedPredictUp)
 9438                            },
 9439                        )
 9440                        .child(Label::new("Jump to Edit")),
 9441                )
 9442            }
 9443            EditPrediction::MoveOutside { snapshot, .. } => {
 9444                let file_name = snapshot
 9445                    .file()
 9446                    .map(|file| file.file_name(cx))
 9447                    .unwrap_or("untitled");
 9448                Some(
 9449                    h_flex()
 9450                        .px_2()
 9451                        .gap_2()
 9452                        .flex_1()
 9453                        .child(Icon::new(IconName::ZedPredict))
 9454                        .child(Label::new(format!("Jump to {file_name}"))),
 9455                )
 9456            }
 9457            EditPrediction::Edit {
 9458                edits,
 9459                edit_preview,
 9460                snapshot,
 9461                display_mode: _,
 9462            } => {
 9463                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9464
 9465                let (highlighted_edits, has_more_lines) =
 9466                    if let Some(edit_preview) = edit_preview.as_ref() {
 9467                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9468                            .first_line_preview()
 9469                    } else {
 9470                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9471                    };
 9472
 9473                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9474                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9475
 9476                let preview = h_flex()
 9477                    .gap_1()
 9478                    .min_w_16()
 9479                    .child(styled_text)
 9480                    .when(has_more_lines, |parent| parent.child(""));
 9481
 9482                let left = if supports_jump && first_edit_row != cursor_point.row {
 9483                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9484                        .into_any_element()
 9485                } else {
 9486                    let icon_name =
 9487                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9488                    Icon::new(icon_name).into_any_element()
 9489                };
 9490
 9491                Some(
 9492                    h_flex()
 9493                        .h_full()
 9494                        .flex_1()
 9495                        .gap_2()
 9496                        .pr_1()
 9497                        .overflow_x_hidden()
 9498                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9499                        .child(left)
 9500                        .child(preview),
 9501                )
 9502            }
 9503        }
 9504    }
 9505
 9506    pub fn render_context_menu(
 9507        &self,
 9508        style: &EditorStyle,
 9509        max_height_in_lines: u32,
 9510        window: &mut Window,
 9511        cx: &mut Context<Editor>,
 9512    ) -> Option<AnyElement> {
 9513        let menu = self.context_menu.borrow();
 9514        let menu = menu.as_ref()?;
 9515        if !menu.visible() {
 9516            return None;
 9517        };
 9518        Some(menu.render(style, max_height_in_lines, window, cx))
 9519    }
 9520
 9521    fn render_context_menu_aside(
 9522        &mut self,
 9523        max_size: Size<Pixels>,
 9524        window: &mut Window,
 9525        cx: &mut Context<Editor>,
 9526    ) -> Option<AnyElement> {
 9527        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9528            if menu.visible() {
 9529                menu.render_aside(max_size, window, cx)
 9530            } else {
 9531                None
 9532            }
 9533        })
 9534    }
 9535
 9536    fn hide_context_menu(
 9537        &mut self,
 9538        window: &mut Window,
 9539        cx: &mut Context<Self>,
 9540    ) -> Option<CodeContextMenu> {
 9541        cx.notify();
 9542        self.completion_tasks.clear();
 9543        let context_menu = self.context_menu.borrow_mut().take();
 9544        self.stale_edit_prediction_in_menu.take();
 9545        self.update_visible_edit_prediction(window, cx);
 9546        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9547            && let Some(completion_provider) = &self.completion_provider
 9548        {
 9549            completion_provider.selection_changed(None, window, cx);
 9550        }
 9551        context_menu
 9552    }
 9553
 9554    fn show_snippet_choices(
 9555        &mut self,
 9556        choices: &Vec<String>,
 9557        selection: Range<Anchor>,
 9558        cx: &mut Context<Self>,
 9559    ) {
 9560        let Some((_, buffer, _)) = self
 9561            .buffer()
 9562            .read(cx)
 9563            .excerpt_containing(selection.start, cx)
 9564        else {
 9565            return;
 9566        };
 9567        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9568        else {
 9569            return;
 9570        };
 9571        if buffer != end_buffer {
 9572            log::error!("expected anchor range to have matching buffer IDs");
 9573            return;
 9574        }
 9575
 9576        let id = post_inc(&mut self.next_completion_id);
 9577        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9578        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9579            CompletionsMenu::new_snippet_choices(
 9580                id,
 9581                true,
 9582                choices,
 9583                selection,
 9584                buffer,
 9585                snippet_sort_order,
 9586            ),
 9587        ));
 9588    }
 9589
 9590    pub fn insert_snippet(
 9591        &mut self,
 9592        insertion_ranges: &[Range<usize>],
 9593        snippet: Snippet,
 9594        window: &mut Window,
 9595        cx: &mut Context<Self>,
 9596    ) -> Result<()> {
 9597        struct Tabstop<T> {
 9598            is_end_tabstop: bool,
 9599            ranges: Vec<Range<T>>,
 9600            choices: Option<Vec<String>>,
 9601        }
 9602
 9603        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9604            let snippet_text: Arc<str> = snippet.text.clone().into();
 9605            let edits = insertion_ranges
 9606                .iter()
 9607                .cloned()
 9608                .map(|range| (range, snippet_text.clone()));
 9609            let autoindent_mode = AutoindentMode::Block {
 9610                original_indent_columns: Vec::new(),
 9611            };
 9612            buffer.edit(edits, Some(autoindent_mode), cx);
 9613
 9614            let snapshot = &*buffer.read(cx);
 9615            let snippet = &snippet;
 9616            snippet
 9617                .tabstops
 9618                .iter()
 9619                .map(|tabstop| {
 9620                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9621                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9622                    });
 9623                    let mut tabstop_ranges = tabstop
 9624                        .ranges
 9625                        .iter()
 9626                        .flat_map(|tabstop_range| {
 9627                            let mut delta = 0_isize;
 9628                            insertion_ranges.iter().map(move |insertion_range| {
 9629                                let insertion_start = insertion_range.start as isize + delta;
 9630                                delta +=
 9631                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9632
 9633                                let start = ((insertion_start + tabstop_range.start) as usize)
 9634                                    .min(snapshot.len());
 9635                                let end = ((insertion_start + tabstop_range.end) as usize)
 9636                                    .min(snapshot.len());
 9637                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9638                            })
 9639                        })
 9640                        .collect::<Vec<_>>();
 9641                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9642
 9643                    Tabstop {
 9644                        is_end_tabstop,
 9645                        ranges: tabstop_ranges,
 9646                        choices: tabstop.choices.clone(),
 9647                    }
 9648                })
 9649                .collect::<Vec<_>>()
 9650        });
 9651        if let Some(tabstop) = tabstops.first() {
 9652            self.change_selections(Default::default(), window, cx, |s| {
 9653                // Reverse order so that the first range is the newest created selection.
 9654                // Completions will use it and autoscroll will prioritize it.
 9655                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9656            });
 9657
 9658            if let Some(choices) = &tabstop.choices
 9659                && let Some(selection) = tabstop.ranges.first()
 9660            {
 9661                self.show_snippet_choices(choices, selection.clone(), cx)
 9662            }
 9663
 9664            // If we're already at the last tabstop and it's at the end of the snippet,
 9665            // we're done, we don't need to keep the state around.
 9666            if !tabstop.is_end_tabstop {
 9667                let choices = tabstops
 9668                    .iter()
 9669                    .map(|tabstop| tabstop.choices.clone())
 9670                    .collect();
 9671
 9672                let ranges = tabstops
 9673                    .into_iter()
 9674                    .map(|tabstop| tabstop.ranges)
 9675                    .collect::<Vec<_>>();
 9676
 9677                self.snippet_stack.push(SnippetState {
 9678                    active_index: 0,
 9679                    ranges,
 9680                    choices,
 9681                });
 9682            }
 9683
 9684            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9685            if self.autoclose_regions.is_empty() {
 9686                let snapshot = self.buffer.read(cx).snapshot(cx);
 9687                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9688                    let selection_head = selection.head();
 9689                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9690                        continue;
 9691                    };
 9692
 9693                    let mut bracket_pair = None;
 9694                    let max_lookup_length = scope
 9695                        .brackets()
 9696                        .map(|(pair, _)| {
 9697                            pair.start
 9698                                .as_str()
 9699                                .chars()
 9700                                .count()
 9701                                .max(pair.end.as_str().chars().count())
 9702                        })
 9703                        .max();
 9704                    if let Some(max_lookup_length) = max_lookup_length {
 9705                        let next_text = snapshot
 9706                            .chars_at(selection_head)
 9707                            .take(max_lookup_length)
 9708                            .collect::<String>();
 9709                        let prev_text = snapshot
 9710                            .reversed_chars_at(selection_head)
 9711                            .take(max_lookup_length)
 9712                            .collect::<String>();
 9713
 9714                        for (pair, enabled) in scope.brackets() {
 9715                            if enabled
 9716                                && pair.close
 9717                                && prev_text.starts_with(pair.start.as_str())
 9718                                && next_text.starts_with(pair.end.as_str())
 9719                            {
 9720                                bracket_pair = Some(pair.clone());
 9721                                break;
 9722                            }
 9723                        }
 9724                    }
 9725
 9726                    if let Some(pair) = bracket_pair {
 9727                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9728                        let autoclose_enabled =
 9729                            self.use_autoclose && snapshot_settings.use_autoclose;
 9730                        if autoclose_enabled {
 9731                            let start = snapshot.anchor_after(selection_head);
 9732                            let end = snapshot.anchor_after(selection_head);
 9733                            self.autoclose_regions.push(AutocloseRegion {
 9734                                selection_id: selection.id,
 9735                                range: start..end,
 9736                                pair,
 9737                            });
 9738                        }
 9739                    }
 9740                }
 9741            }
 9742        }
 9743        Ok(())
 9744    }
 9745
 9746    pub fn move_to_next_snippet_tabstop(
 9747        &mut self,
 9748        window: &mut Window,
 9749        cx: &mut Context<Self>,
 9750    ) -> bool {
 9751        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9752    }
 9753
 9754    pub fn move_to_prev_snippet_tabstop(
 9755        &mut self,
 9756        window: &mut Window,
 9757        cx: &mut Context<Self>,
 9758    ) -> bool {
 9759        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9760    }
 9761
 9762    pub fn move_to_snippet_tabstop(
 9763        &mut self,
 9764        bias: Bias,
 9765        window: &mut Window,
 9766        cx: &mut Context<Self>,
 9767    ) -> bool {
 9768        if let Some(mut snippet) = self.snippet_stack.pop() {
 9769            match bias {
 9770                Bias::Left => {
 9771                    if snippet.active_index > 0 {
 9772                        snippet.active_index -= 1;
 9773                    } else {
 9774                        self.snippet_stack.push(snippet);
 9775                        return false;
 9776                    }
 9777                }
 9778                Bias::Right => {
 9779                    if snippet.active_index + 1 < snippet.ranges.len() {
 9780                        snippet.active_index += 1;
 9781                    } else {
 9782                        self.snippet_stack.push(snippet);
 9783                        return false;
 9784                    }
 9785                }
 9786            }
 9787            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9788                self.change_selections(Default::default(), window, cx, |s| {
 9789                    // Reverse order so that the first range is the newest created selection.
 9790                    // Completions will use it and autoscroll will prioritize it.
 9791                    s.select_ranges(current_ranges.iter().rev().cloned())
 9792                });
 9793
 9794                if let Some(choices) = &snippet.choices[snippet.active_index]
 9795                    && let Some(selection) = current_ranges.first()
 9796                {
 9797                    self.show_snippet_choices(choices, selection.clone(), cx);
 9798                }
 9799
 9800                // If snippet state is not at the last tabstop, push it back on the stack
 9801                if snippet.active_index + 1 < snippet.ranges.len() {
 9802                    self.snippet_stack.push(snippet);
 9803                }
 9804                return true;
 9805            }
 9806        }
 9807
 9808        false
 9809    }
 9810
 9811    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9812        self.transact(window, cx, |this, window, cx| {
 9813            this.select_all(&SelectAll, window, cx);
 9814            this.insert("", window, cx);
 9815        });
 9816    }
 9817
 9818    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9819        if self.read_only(cx) {
 9820            return;
 9821        }
 9822        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9823        self.transact(window, cx, |this, window, cx| {
 9824            this.select_autoclose_pair(window, cx);
 9825
 9826            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9827
 9828            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9829            if !this.linked_edit_ranges.is_empty() {
 9830                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9831                let snapshot = this.buffer.read(cx).snapshot(cx);
 9832
 9833                for selection in selections.iter() {
 9834                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9835                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9836                    if selection_start.buffer_id != selection_end.buffer_id {
 9837                        continue;
 9838                    }
 9839                    if let Some(ranges) =
 9840                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9841                    {
 9842                        for (buffer, entries) in ranges {
 9843                            linked_ranges.entry(buffer).or_default().extend(entries);
 9844                        }
 9845                    }
 9846                }
 9847            }
 9848
 9849            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9850            for selection in &mut selections {
 9851                if selection.is_empty() {
 9852                    let old_head = selection.head();
 9853                    let mut new_head =
 9854                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9855                            .to_point(&display_map);
 9856                    if let Some((buffer, line_buffer_range)) = display_map
 9857                        .buffer_snapshot()
 9858                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9859                    {
 9860                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9861                        let indent_len = match indent_size.kind {
 9862                            IndentKind::Space => {
 9863                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9864                            }
 9865                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9866                        };
 9867                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9868                            let indent_len = indent_len.get();
 9869                            new_head = cmp::min(
 9870                                new_head,
 9871                                MultiBufferPoint::new(
 9872                                    old_head.row,
 9873                                    ((old_head.column - 1) / indent_len) * indent_len,
 9874                                ),
 9875                            );
 9876                        }
 9877                    }
 9878
 9879                    selection.set_head(new_head, SelectionGoal::None);
 9880                }
 9881            }
 9882
 9883            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9884            this.insert("", window, cx);
 9885            let empty_str: Arc<str> = Arc::from("");
 9886            for (buffer, edits) in linked_ranges {
 9887                let snapshot = buffer.read(cx).snapshot();
 9888                use text::ToPoint as TP;
 9889
 9890                let edits = edits
 9891                    .into_iter()
 9892                    .map(|range| {
 9893                        let end_point = TP::to_point(&range.end, &snapshot);
 9894                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9895
 9896                        if end_point == start_point {
 9897                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9898                                .saturating_sub(1);
 9899                            start_point =
 9900                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9901                        };
 9902
 9903                        (start_point..end_point, empty_str.clone())
 9904                    })
 9905                    .sorted_by_key(|(range, _)| range.start)
 9906                    .collect::<Vec<_>>();
 9907                buffer.update(cx, |this, cx| {
 9908                    this.edit(edits, None, cx);
 9909                })
 9910            }
 9911            this.refresh_edit_prediction(true, false, window, cx);
 9912            refresh_linked_ranges(this, window, cx);
 9913        });
 9914    }
 9915
 9916    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9917        if self.read_only(cx) {
 9918            return;
 9919        }
 9920        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9921        self.transact(window, cx, |this, window, cx| {
 9922            this.change_selections(Default::default(), window, cx, |s| {
 9923                s.move_with(|map, selection| {
 9924                    if selection.is_empty() {
 9925                        let cursor = movement::right(map, selection.head());
 9926                        selection.end = cursor;
 9927                        selection.reversed = true;
 9928                        selection.goal = SelectionGoal::None;
 9929                    }
 9930                })
 9931            });
 9932            this.insert("", window, cx);
 9933            this.refresh_edit_prediction(true, false, window, cx);
 9934        });
 9935    }
 9936
 9937    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9938        if self.mode.is_single_line() {
 9939            cx.propagate();
 9940            return;
 9941        }
 9942
 9943        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9944        if self.move_to_prev_snippet_tabstop(window, cx) {
 9945            return;
 9946        }
 9947        self.outdent(&Outdent, window, cx);
 9948    }
 9949
 9950    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9951        if self.mode.is_single_line() {
 9952            cx.propagate();
 9953            return;
 9954        }
 9955
 9956        if self.move_to_next_snippet_tabstop(window, cx) {
 9957            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9958            return;
 9959        }
 9960        if self.read_only(cx) {
 9961            return;
 9962        }
 9963        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9964        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 9965        let buffer = self.buffer.read(cx);
 9966        let snapshot = buffer.snapshot(cx);
 9967        let rows_iter = selections.iter().map(|s| s.head().row);
 9968        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9969
 9970        let has_some_cursor_in_whitespace = selections
 9971            .iter()
 9972            .filter(|selection| selection.is_empty())
 9973            .any(|selection| {
 9974                let cursor = selection.head();
 9975                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9976                cursor.column < current_indent.len
 9977            });
 9978
 9979        let mut edits = Vec::new();
 9980        let mut prev_edited_row = 0;
 9981        let mut row_delta = 0;
 9982        for selection in &mut selections {
 9983            if selection.start.row != prev_edited_row {
 9984                row_delta = 0;
 9985            }
 9986            prev_edited_row = selection.end.row;
 9987
 9988            // If the selection is non-empty, then increase the indentation of the selected lines.
 9989            if !selection.is_empty() {
 9990                row_delta =
 9991                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9992                continue;
 9993            }
 9994
 9995            let cursor = selection.head();
 9996            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9997            if let Some(suggested_indent) =
 9998                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9999            {
10000                // Don't do anything if already at suggested indent
10001                // and there is any other cursor which is not
10002                if has_some_cursor_in_whitespace
10003                    && cursor.column == current_indent.len
10004                    && current_indent.len == suggested_indent.len
10005                {
10006                    continue;
10007                }
10008
10009                // Adjust line and move cursor to suggested indent
10010                // if cursor is not at suggested indent
10011                if cursor.column < suggested_indent.len
10012                    && cursor.column <= current_indent.len
10013                    && current_indent.len <= suggested_indent.len
10014                {
10015                    selection.start = Point::new(cursor.row, suggested_indent.len);
10016                    selection.end = selection.start;
10017                    if row_delta == 0 {
10018                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10019                            cursor.row,
10020                            current_indent,
10021                            suggested_indent,
10022                        ));
10023                        row_delta = suggested_indent.len - current_indent.len;
10024                    }
10025                    continue;
10026                }
10027
10028                // If current indent is more than suggested indent
10029                // only move cursor to current indent and skip indent
10030                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10031                    selection.start = Point::new(cursor.row, current_indent.len);
10032                    selection.end = selection.start;
10033                    continue;
10034                }
10035            }
10036
10037            // Otherwise, insert a hard or soft tab.
10038            let settings = buffer.language_settings_at(cursor, cx);
10039            let tab_size = if settings.hard_tabs {
10040                IndentSize::tab()
10041            } else {
10042                let tab_size = settings.tab_size.get();
10043                let indent_remainder = snapshot
10044                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10045                    .flat_map(str::chars)
10046                    .fold(row_delta % tab_size, |counter: u32, c| {
10047                        if c == '\t' {
10048                            0
10049                        } else {
10050                            (counter + 1) % tab_size
10051                        }
10052                    });
10053
10054                let chars_to_next_tab_stop = tab_size - indent_remainder;
10055                IndentSize::spaces(chars_to_next_tab_stop)
10056            };
10057            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10058            selection.end = selection.start;
10059            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10060            row_delta += tab_size.len;
10061        }
10062
10063        self.transact(window, cx, |this, window, cx| {
10064            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10065            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10066            this.refresh_edit_prediction(true, false, window, cx);
10067        });
10068    }
10069
10070    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10071        if self.read_only(cx) {
10072            return;
10073        }
10074        if self.mode.is_single_line() {
10075            cx.propagate();
10076            return;
10077        }
10078
10079        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10080        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10081        let mut prev_edited_row = 0;
10082        let mut row_delta = 0;
10083        let mut edits = Vec::new();
10084        let buffer = self.buffer.read(cx);
10085        let snapshot = buffer.snapshot(cx);
10086        for selection in &mut selections {
10087            if selection.start.row != prev_edited_row {
10088                row_delta = 0;
10089            }
10090            prev_edited_row = selection.end.row;
10091
10092            row_delta =
10093                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10094        }
10095
10096        self.transact(window, cx, |this, window, cx| {
10097            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10098            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10099        });
10100    }
10101
10102    fn indent_selection(
10103        buffer: &MultiBuffer,
10104        snapshot: &MultiBufferSnapshot,
10105        selection: &mut Selection<Point>,
10106        edits: &mut Vec<(Range<Point>, String)>,
10107        delta_for_start_row: u32,
10108        cx: &App,
10109    ) -> u32 {
10110        let settings = buffer.language_settings_at(selection.start, cx);
10111        let tab_size = settings.tab_size.get();
10112        let indent_kind = if settings.hard_tabs {
10113            IndentKind::Tab
10114        } else {
10115            IndentKind::Space
10116        };
10117        let mut start_row = selection.start.row;
10118        let mut end_row = selection.end.row + 1;
10119
10120        // If a selection ends at the beginning of a line, don't indent
10121        // that last line.
10122        if selection.end.column == 0 && selection.end.row > selection.start.row {
10123            end_row -= 1;
10124        }
10125
10126        // Avoid re-indenting a row that has already been indented by a
10127        // previous selection, but still update this selection's column
10128        // to reflect that indentation.
10129        if delta_for_start_row > 0 {
10130            start_row += 1;
10131            selection.start.column += delta_for_start_row;
10132            if selection.end.row == selection.start.row {
10133                selection.end.column += delta_for_start_row;
10134            }
10135        }
10136
10137        let mut delta_for_end_row = 0;
10138        let has_multiple_rows = start_row + 1 != end_row;
10139        for row in start_row..end_row {
10140            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10141            let indent_delta = match (current_indent.kind, indent_kind) {
10142                (IndentKind::Space, IndentKind::Space) => {
10143                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10144                    IndentSize::spaces(columns_to_next_tab_stop)
10145                }
10146                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10147                (_, IndentKind::Tab) => IndentSize::tab(),
10148            };
10149
10150            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10151                0
10152            } else {
10153                selection.start.column
10154            };
10155            let row_start = Point::new(row, start);
10156            edits.push((
10157                row_start..row_start,
10158                indent_delta.chars().collect::<String>(),
10159            ));
10160
10161            // Update this selection's endpoints to reflect the indentation.
10162            if row == selection.start.row {
10163                selection.start.column += indent_delta.len;
10164            }
10165            if row == selection.end.row {
10166                selection.end.column += indent_delta.len;
10167                delta_for_end_row = indent_delta.len;
10168            }
10169        }
10170
10171        if selection.start.row == selection.end.row {
10172            delta_for_start_row + delta_for_end_row
10173        } else {
10174            delta_for_end_row
10175        }
10176    }
10177
10178    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10179        if self.read_only(cx) {
10180            return;
10181        }
10182        if self.mode.is_single_line() {
10183            cx.propagate();
10184            return;
10185        }
10186
10187        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10188        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10189        let selections = self.selections.all::<Point>(&display_map);
10190        let mut deletion_ranges = Vec::new();
10191        let mut last_outdent = None;
10192        {
10193            let buffer = self.buffer.read(cx);
10194            let snapshot = buffer.snapshot(cx);
10195            for selection in &selections {
10196                let settings = buffer.language_settings_at(selection.start, cx);
10197                let tab_size = settings.tab_size.get();
10198                let mut rows = selection.spanned_rows(false, &display_map);
10199
10200                // Avoid re-outdenting a row that has already been outdented by a
10201                // previous selection.
10202                if let Some(last_row) = last_outdent
10203                    && last_row == rows.start
10204                {
10205                    rows.start = rows.start.next_row();
10206                }
10207                let has_multiple_rows = rows.len() > 1;
10208                for row in rows.iter_rows() {
10209                    let indent_size = snapshot.indent_size_for_line(row);
10210                    if indent_size.len > 0 {
10211                        let deletion_len = match indent_size.kind {
10212                            IndentKind::Space => {
10213                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10214                                if columns_to_prev_tab_stop == 0 {
10215                                    tab_size
10216                                } else {
10217                                    columns_to_prev_tab_stop
10218                                }
10219                            }
10220                            IndentKind::Tab => 1,
10221                        };
10222                        let start = if has_multiple_rows
10223                            || deletion_len > selection.start.column
10224                            || indent_size.len < selection.start.column
10225                        {
10226                            0
10227                        } else {
10228                            selection.start.column - deletion_len
10229                        };
10230                        deletion_ranges.push(
10231                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10232                        );
10233                        last_outdent = Some(row);
10234                    }
10235                }
10236            }
10237        }
10238
10239        self.transact(window, cx, |this, window, cx| {
10240            this.buffer.update(cx, |buffer, cx| {
10241                let empty_str: Arc<str> = Arc::default();
10242                buffer.edit(
10243                    deletion_ranges
10244                        .into_iter()
10245                        .map(|range| (range, empty_str.clone())),
10246                    None,
10247                    cx,
10248                );
10249            });
10250            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10251            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10252        });
10253    }
10254
10255    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10256        if self.read_only(cx) {
10257            return;
10258        }
10259        if self.mode.is_single_line() {
10260            cx.propagate();
10261            return;
10262        }
10263
10264        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10265        let selections = self
10266            .selections
10267            .all::<usize>(&self.display_snapshot(cx))
10268            .into_iter()
10269            .map(|s| s.range());
10270
10271        self.transact(window, cx, |this, window, cx| {
10272            this.buffer.update(cx, |buffer, cx| {
10273                buffer.autoindent_ranges(selections, cx);
10274            });
10275            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10276            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10277        });
10278    }
10279
10280    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10281        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10282        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10283        let selections = self.selections.all::<Point>(&display_map);
10284
10285        let mut new_cursors = Vec::new();
10286        let mut edit_ranges = Vec::new();
10287        let mut selections = selections.iter().peekable();
10288        while let Some(selection) = selections.next() {
10289            let mut rows = selection.spanned_rows(false, &display_map);
10290
10291            // Accumulate contiguous regions of rows that we want to delete.
10292            while let Some(next_selection) = selections.peek() {
10293                let next_rows = next_selection.spanned_rows(false, &display_map);
10294                if next_rows.start <= rows.end {
10295                    rows.end = next_rows.end;
10296                    selections.next().unwrap();
10297                } else {
10298                    break;
10299                }
10300            }
10301
10302            let buffer = display_map.buffer_snapshot();
10303            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10304            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10305                // If there's a line after the range, delete the \n from the end of the row range
10306                (
10307                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10308                    rows.end,
10309                )
10310            } else {
10311                // If there isn't a line after the range, delete the \n from the line before the
10312                // start of the row range
10313                edit_start = edit_start.saturating_sub(1);
10314                (buffer.len(), rows.start.previous_row())
10315            };
10316
10317            let text_layout_details = self.text_layout_details(window);
10318            let x = display_map.x_for_display_point(
10319                selection.head().to_display_point(&display_map),
10320                &text_layout_details,
10321            );
10322            let row = Point::new(target_row.0, 0)
10323                .to_display_point(&display_map)
10324                .row();
10325            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10326
10327            new_cursors.push((
10328                selection.id,
10329                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10330                SelectionGoal::None,
10331            ));
10332            edit_ranges.push(edit_start..edit_end);
10333        }
10334
10335        self.transact(window, cx, |this, window, cx| {
10336            let buffer = this.buffer.update(cx, |buffer, cx| {
10337                let empty_str: Arc<str> = Arc::default();
10338                buffer.edit(
10339                    edit_ranges
10340                        .into_iter()
10341                        .map(|range| (range, empty_str.clone())),
10342                    None,
10343                    cx,
10344                );
10345                buffer.snapshot(cx)
10346            });
10347            let new_selections = new_cursors
10348                .into_iter()
10349                .map(|(id, cursor, goal)| {
10350                    let cursor = cursor.to_point(&buffer);
10351                    Selection {
10352                        id,
10353                        start: cursor,
10354                        end: cursor,
10355                        reversed: false,
10356                        goal,
10357                    }
10358                })
10359                .collect();
10360
10361            this.change_selections(Default::default(), window, cx, |s| {
10362                s.select(new_selections);
10363            });
10364        });
10365    }
10366
10367    pub fn join_lines_impl(
10368        &mut self,
10369        insert_whitespace: bool,
10370        window: &mut Window,
10371        cx: &mut Context<Self>,
10372    ) {
10373        if self.read_only(cx) {
10374            return;
10375        }
10376        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10377        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10378            let start = MultiBufferRow(selection.start.row);
10379            // Treat single line selections as if they include the next line. Otherwise this action
10380            // would do nothing for single line selections individual cursors.
10381            let end = if selection.start.row == selection.end.row {
10382                MultiBufferRow(selection.start.row + 1)
10383            } else {
10384                MultiBufferRow(selection.end.row)
10385            };
10386
10387            if let Some(last_row_range) = row_ranges.last_mut()
10388                && start <= last_row_range.end
10389            {
10390                last_row_range.end = end;
10391                continue;
10392            }
10393            row_ranges.push(start..end);
10394        }
10395
10396        let snapshot = self.buffer.read(cx).snapshot(cx);
10397        let mut cursor_positions = Vec::new();
10398        for row_range in &row_ranges {
10399            let anchor = snapshot.anchor_before(Point::new(
10400                row_range.end.previous_row().0,
10401                snapshot.line_len(row_range.end.previous_row()),
10402            ));
10403            cursor_positions.push(anchor..anchor);
10404        }
10405
10406        self.transact(window, cx, |this, window, cx| {
10407            for row_range in row_ranges.into_iter().rev() {
10408                for row in row_range.iter_rows().rev() {
10409                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10410                    let next_line_row = row.next_row();
10411                    let indent = snapshot.indent_size_for_line(next_line_row);
10412                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10413
10414                    let replace =
10415                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10416                            " "
10417                        } else {
10418                            ""
10419                        };
10420
10421                    this.buffer.update(cx, |buffer, cx| {
10422                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10423                    });
10424                }
10425            }
10426
10427            this.change_selections(Default::default(), window, cx, |s| {
10428                s.select_anchor_ranges(cursor_positions)
10429            });
10430        });
10431    }
10432
10433    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10434        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10435        self.join_lines_impl(true, window, cx);
10436    }
10437
10438    pub fn sort_lines_case_sensitive(
10439        &mut self,
10440        _: &SortLinesCaseSensitive,
10441        window: &mut Window,
10442        cx: &mut Context<Self>,
10443    ) {
10444        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10445    }
10446
10447    pub fn sort_lines_by_length(
10448        &mut self,
10449        _: &SortLinesByLength,
10450        window: &mut Window,
10451        cx: &mut Context<Self>,
10452    ) {
10453        self.manipulate_immutable_lines(window, cx, |lines| {
10454            lines.sort_by_key(|&line| line.chars().count())
10455        })
10456    }
10457
10458    pub fn sort_lines_case_insensitive(
10459        &mut self,
10460        _: &SortLinesCaseInsensitive,
10461        window: &mut Window,
10462        cx: &mut Context<Self>,
10463    ) {
10464        self.manipulate_immutable_lines(window, cx, |lines| {
10465            lines.sort_by_key(|line| line.to_lowercase())
10466        })
10467    }
10468
10469    pub fn unique_lines_case_insensitive(
10470        &mut self,
10471        _: &UniqueLinesCaseInsensitive,
10472        window: &mut Window,
10473        cx: &mut Context<Self>,
10474    ) {
10475        self.manipulate_immutable_lines(window, cx, |lines| {
10476            let mut seen = HashSet::default();
10477            lines.retain(|line| seen.insert(line.to_lowercase()));
10478        })
10479    }
10480
10481    pub fn unique_lines_case_sensitive(
10482        &mut self,
10483        _: &UniqueLinesCaseSensitive,
10484        window: &mut Window,
10485        cx: &mut Context<Self>,
10486    ) {
10487        self.manipulate_immutable_lines(window, cx, |lines| {
10488            let mut seen = HashSet::default();
10489            lines.retain(|line| seen.insert(*line));
10490        })
10491    }
10492
10493    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10494        let snapshot = self.buffer.read(cx).snapshot(cx);
10495        for selection in self.selections.disjoint_anchors_arc().iter() {
10496            if snapshot
10497                .language_at(selection.start)
10498                .and_then(|lang| lang.config().wrap_characters.as_ref())
10499                .is_some()
10500            {
10501                return true;
10502            }
10503        }
10504        false
10505    }
10506
10507    fn wrap_selections_in_tag(
10508        &mut self,
10509        _: &WrapSelectionsInTag,
10510        window: &mut Window,
10511        cx: &mut Context<Self>,
10512    ) {
10513        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10514
10515        let snapshot = self.buffer.read(cx).snapshot(cx);
10516
10517        let mut edits = Vec::new();
10518        let mut boundaries = Vec::new();
10519
10520        for selection in self
10521            .selections
10522            .all::<Point>(&self.display_snapshot(cx))
10523            .iter()
10524        {
10525            let Some(wrap_config) = snapshot
10526                .language_at(selection.start)
10527                .and_then(|lang| lang.config().wrap_characters.clone())
10528            else {
10529                continue;
10530            };
10531
10532            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10533            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10534
10535            let start_before = snapshot.anchor_before(selection.start);
10536            let end_after = snapshot.anchor_after(selection.end);
10537
10538            edits.push((start_before..start_before, open_tag));
10539            edits.push((end_after..end_after, close_tag));
10540
10541            boundaries.push((
10542                start_before,
10543                end_after,
10544                wrap_config.start_prefix.len(),
10545                wrap_config.end_suffix.len(),
10546            ));
10547        }
10548
10549        if edits.is_empty() {
10550            return;
10551        }
10552
10553        self.transact(window, cx, |this, window, cx| {
10554            let buffer = this.buffer.update(cx, |buffer, cx| {
10555                buffer.edit(edits, None, cx);
10556                buffer.snapshot(cx)
10557            });
10558
10559            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10560            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10561                boundaries.into_iter()
10562            {
10563                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10564                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10565                new_selections.push(open_offset..open_offset);
10566                new_selections.push(close_offset..close_offset);
10567            }
10568
10569            this.change_selections(Default::default(), window, cx, |s| {
10570                s.select_ranges(new_selections);
10571            });
10572
10573            this.request_autoscroll(Autoscroll::fit(), cx);
10574        });
10575    }
10576
10577    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10578        let Some(project) = self.project.clone() else {
10579            return;
10580        };
10581        self.reload(project, window, cx)
10582            .detach_and_notify_err(window, cx);
10583    }
10584
10585    pub fn restore_file(
10586        &mut self,
10587        _: &::git::RestoreFile,
10588        window: &mut Window,
10589        cx: &mut Context<Self>,
10590    ) {
10591        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10592        let mut buffer_ids = HashSet::default();
10593        let snapshot = self.buffer().read(cx).snapshot(cx);
10594        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10595            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10596        }
10597
10598        let buffer = self.buffer().read(cx);
10599        let ranges = buffer_ids
10600            .into_iter()
10601            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10602            .collect::<Vec<_>>();
10603
10604        self.restore_hunks_in_ranges(ranges, window, cx);
10605    }
10606
10607    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10608        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10609        let selections = self
10610            .selections
10611            .all(&self.display_snapshot(cx))
10612            .into_iter()
10613            .map(|s| s.range())
10614            .collect();
10615        self.restore_hunks_in_ranges(selections, window, cx);
10616    }
10617
10618    pub fn restore_hunks_in_ranges(
10619        &mut self,
10620        ranges: Vec<Range<Point>>,
10621        window: &mut Window,
10622        cx: &mut Context<Editor>,
10623    ) {
10624        let mut revert_changes = HashMap::default();
10625        let chunk_by = self
10626            .snapshot(window, cx)
10627            .hunks_for_ranges(ranges)
10628            .into_iter()
10629            .chunk_by(|hunk| hunk.buffer_id);
10630        for (buffer_id, hunks) in &chunk_by {
10631            let hunks = hunks.collect::<Vec<_>>();
10632            for hunk in &hunks {
10633                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10634            }
10635            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10636        }
10637        drop(chunk_by);
10638        if !revert_changes.is_empty() {
10639            self.transact(window, cx, |editor, window, cx| {
10640                editor.restore(revert_changes, window, cx);
10641            });
10642        }
10643    }
10644
10645    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10646        if let Some(status) = self
10647            .addons
10648            .iter()
10649            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10650        {
10651            return Some(status);
10652        }
10653        self.project
10654            .as_ref()?
10655            .read(cx)
10656            .status_for_buffer_id(buffer_id, cx)
10657    }
10658
10659    pub fn open_active_item_in_terminal(
10660        &mut self,
10661        _: &OpenInTerminal,
10662        window: &mut Window,
10663        cx: &mut Context<Self>,
10664    ) {
10665        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10666            let project_path = buffer.read(cx).project_path(cx)?;
10667            let project = self.project()?.read(cx);
10668            let entry = project.entry_for_path(&project_path, cx)?;
10669            let parent = match &entry.canonical_path {
10670                Some(canonical_path) => canonical_path.to_path_buf(),
10671                None => project.absolute_path(&project_path, cx)?,
10672            }
10673            .parent()?
10674            .to_path_buf();
10675            Some(parent)
10676        }) {
10677            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10678        }
10679    }
10680
10681    fn set_breakpoint_context_menu(
10682        &mut self,
10683        display_row: DisplayRow,
10684        position: Option<Anchor>,
10685        clicked_point: gpui::Point<Pixels>,
10686        window: &mut Window,
10687        cx: &mut Context<Self>,
10688    ) {
10689        let source = self
10690            .buffer
10691            .read(cx)
10692            .snapshot(cx)
10693            .anchor_before(Point::new(display_row.0, 0u32));
10694
10695        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10696
10697        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10698            self,
10699            source,
10700            clicked_point,
10701            context_menu,
10702            window,
10703            cx,
10704        );
10705    }
10706
10707    fn add_edit_breakpoint_block(
10708        &mut self,
10709        anchor: Anchor,
10710        breakpoint: &Breakpoint,
10711        edit_action: BreakpointPromptEditAction,
10712        window: &mut Window,
10713        cx: &mut Context<Self>,
10714    ) {
10715        let weak_editor = cx.weak_entity();
10716        let bp_prompt = cx.new(|cx| {
10717            BreakpointPromptEditor::new(
10718                weak_editor,
10719                anchor,
10720                breakpoint.clone(),
10721                edit_action,
10722                window,
10723                cx,
10724            )
10725        });
10726
10727        let height = bp_prompt.update(cx, |this, cx| {
10728            this.prompt
10729                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10730        });
10731        let cloned_prompt = bp_prompt.clone();
10732        let blocks = vec![BlockProperties {
10733            style: BlockStyle::Sticky,
10734            placement: BlockPlacement::Above(anchor),
10735            height: Some(height),
10736            render: Arc::new(move |cx| {
10737                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10738                cloned_prompt.clone().into_any_element()
10739            }),
10740            priority: 0,
10741        }];
10742
10743        let focus_handle = bp_prompt.focus_handle(cx);
10744        window.focus(&focus_handle);
10745
10746        let block_ids = self.insert_blocks(blocks, None, cx);
10747        bp_prompt.update(cx, |prompt, _| {
10748            prompt.add_block_ids(block_ids);
10749        });
10750    }
10751
10752    pub(crate) fn breakpoint_at_row(
10753        &self,
10754        row: u32,
10755        window: &mut Window,
10756        cx: &mut Context<Self>,
10757    ) -> Option<(Anchor, Breakpoint)> {
10758        let snapshot = self.snapshot(window, cx);
10759        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10760
10761        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10762    }
10763
10764    pub(crate) fn breakpoint_at_anchor(
10765        &self,
10766        breakpoint_position: Anchor,
10767        snapshot: &EditorSnapshot,
10768        cx: &mut Context<Self>,
10769    ) -> Option<(Anchor, Breakpoint)> {
10770        let buffer = self
10771            .buffer
10772            .read(cx)
10773            .buffer_for_anchor(breakpoint_position, cx)?;
10774
10775        let enclosing_excerpt = breakpoint_position.excerpt_id;
10776        let buffer_snapshot = buffer.read(cx).snapshot();
10777
10778        let row = buffer_snapshot
10779            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10780            .row;
10781
10782        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10783        let anchor_end = snapshot
10784            .buffer_snapshot()
10785            .anchor_after(Point::new(row, line_len));
10786
10787        self.breakpoint_store
10788            .as_ref()?
10789            .read_with(cx, |breakpoint_store, cx| {
10790                breakpoint_store
10791                    .breakpoints(
10792                        &buffer,
10793                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10794                        &buffer_snapshot,
10795                        cx,
10796                    )
10797                    .next()
10798                    .and_then(|(bp, _)| {
10799                        let breakpoint_row = buffer_snapshot
10800                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10801                            .row;
10802
10803                        if breakpoint_row == row {
10804                            snapshot
10805                                .buffer_snapshot()
10806                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10807                                .map(|position| (position, bp.bp.clone()))
10808                        } else {
10809                            None
10810                        }
10811                    })
10812            })
10813    }
10814
10815    pub fn edit_log_breakpoint(
10816        &mut self,
10817        _: &EditLogBreakpoint,
10818        window: &mut Window,
10819        cx: &mut Context<Self>,
10820    ) {
10821        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10822            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10823                message: None,
10824                state: BreakpointState::Enabled,
10825                condition: None,
10826                hit_condition: None,
10827            });
10828
10829            self.add_edit_breakpoint_block(
10830                anchor,
10831                &breakpoint,
10832                BreakpointPromptEditAction::Log,
10833                window,
10834                cx,
10835            );
10836        }
10837    }
10838
10839    fn breakpoints_at_cursors(
10840        &self,
10841        window: &mut Window,
10842        cx: &mut Context<Self>,
10843    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10844        let snapshot = self.snapshot(window, cx);
10845        let cursors = self
10846            .selections
10847            .disjoint_anchors_arc()
10848            .iter()
10849            .map(|selection| {
10850                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10851
10852                let breakpoint_position = self
10853                    .breakpoint_at_row(cursor_position.row, window, cx)
10854                    .map(|bp| bp.0)
10855                    .unwrap_or_else(|| {
10856                        snapshot
10857                            .display_snapshot
10858                            .buffer_snapshot()
10859                            .anchor_after(Point::new(cursor_position.row, 0))
10860                    });
10861
10862                let breakpoint = self
10863                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10864                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10865
10866                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10867            })
10868            // 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.
10869            .collect::<HashMap<Anchor, _>>();
10870
10871        cursors.into_iter().collect()
10872    }
10873
10874    pub fn enable_breakpoint(
10875        &mut self,
10876        _: &crate::actions::EnableBreakpoint,
10877        window: &mut Window,
10878        cx: &mut Context<Self>,
10879    ) {
10880        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10881            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10882                continue;
10883            };
10884            self.edit_breakpoint_at_anchor(
10885                anchor,
10886                breakpoint,
10887                BreakpointEditAction::InvertState,
10888                cx,
10889            );
10890        }
10891    }
10892
10893    pub fn disable_breakpoint(
10894        &mut self,
10895        _: &crate::actions::DisableBreakpoint,
10896        window: &mut Window,
10897        cx: &mut Context<Self>,
10898    ) {
10899        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10900            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10901                continue;
10902            };
10903            self.edit_breakpoint_at_anchor(
10904                anchor,
10905                breakpoint,
10906                BreakpointEditAction::InvertState,
10907                cx,
10908            );
10909        }
10910    }
10911
10912    pub fn toggle_breakpoint(
10913        &mut self,
10914        _: &crate::actions::ToggleBreakpoint,
10915        window: &mut Window,
10916        cx: &mut Context<Self>,
10917    ) {
10918        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10919            if let Some(breakpoint) = breakpoint {
10920                self.edit_breakpoint_at_anchor(
10921                    anchor,
10922                    breakpoint,
10923                    BreakpointEditAction::Toggle,
10924                    cx,
10925                );
10926            } else {
10927                self.edit_breakpoint_at_anchor(
10928                    anchor,
10929                    Breakpoint::new_standard(),
10930                    BreakpointEditAction::Toggle,
10931                    cx,
10932                );
10933            }
10934        }
10935    }
10936
10937    pub fn edit_breakpoint_at_anchor(
10938        &mut self,
10939        breakpoint_position: Anchor,
10940        breakpoint: Breakpoint,
10941        edit_action: BreakpointEditAction,
10942        cx: &mut Context<Self>,
10943    ) {
10944        let Some(breakpoint_store) = &self.breakpoint_store else {
10945            return;
10946        };
10947
10948        let Some(buffer) = self
10949            .buffer
10950            .read(cx)
10951            .buffer_for_anchor(breakpoint_position, cx)
10952        else {
10953            return;
10954        };
10955
10956        breakpoint_store.update(cx, |breakpoint_store, cx| {
10957            breakpoint_store.toggle_breakpoint(
10958                buffer,
10959                BreakpointWithPosition {
10960                    position: breakpoint_position.text_anchor,
10961                    bp: breakpoint,
10962                },
10963                edit_action,
10964                cx,
10965            );
10966        });
10967
10968        cx.notify();
10969    }
10970
10971    #[cfg(any(test, feature = "test-support"))]
10972    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10973        self.breakpoint_store.clone()
10974    }
10975
10976    pub fn prepare_restore_change(
10977        &self,
10978        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10979        hunk: &MultiBufferDiffHunk,
10980        cx: &mut App,
10981    ) -> Option<()> {
10982        if hunk.is_created_file() {
10983            return None;
10984        }
10985        let buffer = self.buffer.read(cx);
10986        let diff = buffer.diff_for(hunk.buffer_id)?;
10987        let buffer = buffer.buffer(hunk.buffer_id)?;
10988        let buffer = buffer.read(cx);
10989        let original_text = diff
10990            .read(cx)
10991            .base_text()
10992            .as_rope()
10993            .slice(hunk.diff_base_byte_range.clone());
10994        let buffer_snapshot = buffer.snapshot();
10995        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10996        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10997            probe
10998                .0
10999                .start
11000                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11001                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11002        }) {
11003            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11004            Some(())
11005        } else {
11006            None
11007        }
11008    }
11009
11010    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11011        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11012    }
11013
11014    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11015        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11016    }
11017
11018    fn manipulate_lines<M>(
11019        &mut self,
11020        window: &mut Window,
11021        cx: &mut Context<Self>,
11022        mut manipulate: M,
11023    ) where
11024        M: FnMut(&str) -> LineManipulationResult,
11025    {
11026        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11027
11028        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11029        let buffer = self.buffer.read(cx).snapshot(cx);
11030
11031        let mut edits = Vec::new();
11032
11033        let selections = self.selections.all::<Point>(&display_map);
11034        let mut selections = selections.iter().peekable();
11035        let mut contiguous_row_selections = Vec::new();
11036        let mut new_selections = Vec::new();
11037        let mut added_lines = 0;
11038        let mut removed_lines = 0;
11039
11040        while let Some(selection) = selections.next() {
11041            let (start_row, end_row) = consume_contiguous_rows(
11042                &mut contiguous_row_selections,
11043                selection,
11044                &display_map,
11045                &mut selections,
11046            );
11047
11048            let start_point = Point::new(start_row.0, 0);
11049            let end_point = Point::new(
11050                end_row.previous_row().0,
11051                buffer.line_len(end_row.previous_row()),
11052            );
11053            let text = buffer
11054                .text_for_range(start_point..end_point)
11055                .collect::<String>();
11056
11057            let LineManipulationResult {
11058                new_text,
11059                line_count_before,
11060                line_count_after,
11061            } = manipulate(&text);
11062
11063            edits.push((start_point..end_point, new_text));
11064
11065            // Selections must change based on added and removed line count
11066            let start_row =
11067                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11068            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11069            new_selections.push(Selection {
11070                id: selection.id,
11071                start: start_row,
11072                end: end_row,
11073                goal: SelectionGoal::None,
11074                reversed: selection.reversed,
11075            });
11076
11077            if line_count_after > line_count_before {
11078                added_lines += line_count_after - line_count_before;
11079            } else if line_count_before > line_count_after {
11080                removed_lines += line_count_before - line_count_after;
11081            }
11082        }
11083
11084        self.transact(window, cx, |this, window, cx| {
11085            let buffer = this.buffer.update(cx, |buffer, cx| {
11086                buffer.edit(edits, None, cx);
11087                buffer.snapshot(cx)
11088            });
11089
11090            // Recalculate offsets on newly edited buffer
11091            let new_selections = new_selections
11092                .iter()
11093                .map(|s| {
11094                    let start_point = Point::new(s.start.0, 0);
11095                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11096                    Selection {
11097                        id: s.id,
11098                        start: buffer.point_to_offset(start_point),
11099                        end: buffer.point_to_offset(end_point),
11100                        goal: s.goal,
11101                        reversed: s.reversed,
11102                    }
11103                })
11104                .collect();
11105
11106            this.change_selections(Default::default(), window, cx, |s| {
11107                s.select(new_selections);
11108            });
11109
11110            this.request_autoscroll(Autoscroll::fit(), cx);
11111        });
11112    }
11113
11114    fn manipulate_immutable_lines<Fn>(
11115        &mut self,
11116        window: &mut Window,
11117        cx: &mut Context<Self>,
11118        mut callback: Fn,
11119    ) where
11120        Fn: FnMut(&mut Vec<&str>),
11121    {
11122        self.manipulate_lines(window, cx, |text| {
11123            let mut lines: Vec<&str> = text.split('\n').collect();
11124            let line_count_before = lines.len();
11125
11126            callback(&mut lines);
11127
11128            LineManipulationResult {
11129                new_text: lines.join("\n"),
11130                line_count_before,
11131                line_count_after: lines.len(),
11132            }
11133        });
11134    }
11135
11136    fn manipulate_mutable_lines<Fn>(
11137        &mut self,
11138        window: &mut Window,
11139        cx: &mut Context<Self>,
11140        mut callback: Fn,
11141    ) where
11142        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11143    {
11144        self.manipulate_lines(window, cx, |text| {
11145            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11146            let line_count_before = lines.len();
11147
11148            callback(&mut lines);
11149
11150            LineManipulationResult {
11151                new_text: lines.join("\n"),
11152                line_count_before,
11153                line_count_after: lines.len(),
11154            }
11155        });
11156    }
11157
11158    pub fn convert_indentation_to_spaces(
11159        &mut self,
11160        _: &ConvertIndentationToSpaces,
11161        window: &mut Window,
11162        cx: &mut Context<Self>,
11163    ) {
11164        let settings = self.buffer.read(cx).language_settings(cx);
11165        let tab_size = settings.tab_size.get() as usize;
11166
11167        self.manipulate_mutable_lines(window, cx, |lines| {
11168            // Allocates a reasonably sized scratch buffer once for the whole loop
11169            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11170            // Avoids recomputing spaces that could be inserted many times
11171            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11172                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11173                .collect();
11174
11175            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11176                let mut chars = line.as_ref().chars();
11177                let mut col = 0;
11178                let mut changed = false;
11179
11180                for ch in chars.by_ref() {
11181                    match ch {
11182                        ' ' => {
11183                            reindented_line.push(' ');
11184                            col += 1;
11185                        }
11186                        '\t' => {
11187                            // \t are converted to spaces depending on the current column
11188                            let spaces_len = tab_size - (col % tab_size);
11189                            reindented_line.extend(&space_cache[spaces_len - 1]);
11190                            col += spaces_len;
11191                            changed = true;
11192                        }
11193                        _ => {
11194                            // If we dont append before break, the character is consumed
11195                            reindented_line.push(ch);
11196                            break;
11197                        }
11198                    }
11199                }
11200
11201                if !changed {
11202                    reindented_line.clear();
11203                    continue;
11204                }
11205                // Append the rest of the line and replace old reference with new one
11206                reindented_line.extend(chars);
11207                *line = Cow::Owned(reindented_line.clone());
11208                reindented_line.clear();
11209            }
11210        });
11211    }
11212
11213    pub fn convert_indentation_to_tabs(
11214        &mut self,
11215        _: &ConvertIndentationToTabs,
11216        window: &mut Window,
11217        cx: &mut Context<Self>,
11218    ) {
11219        let settings = self.buffer.read(cx).language_settings(cx);
11220        let tab_size = settings.tab_size.get() as usize;
11221
11222        self.manipulate_mutable_lines(window, cx, |lines| {
11223            // Allocates a reasonably sized buffer once for the whole loop
11224            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11225            // Avoids recomputing spaces that could be inserted many times
11226            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11227                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11228                .collect();
11229
11230            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11231                let mut chars = line.chars();
11232                let mut spaces_count = 0;
11233                let mut first_non_indent_char = None;
11234                let mut changed = false;
11235
11236                for ch in chars.by_ref() {
11237                    match ch {
11238                        ' ' => {
11239                            // Keep track of spaces. Append \t when we reach tab_size
11240                            spaces_count += 1;
11241                            changed = true;
11242                            if spaces_count == tab_size {
11243                                reindented_line.push('\t');
11244                                spaces_count = 0;
11245                            }
11246                        }
11247                        '\t' => {
11248                            reindented_line.push('\t');
11249                            spaces_count = 0;
11250                        }
11251                        _ => {
11252                            // Dont append it yet, we might have remaining spaces
11253                            first_non_indent_char = Some(ch);
11254                            break;
11255                        }
11256                    }
11257                }
11258
11259                if !changed {
11260                    reindented_line.clear();
11261                    continue;
11262                }
11263                // Remaining spaces that didn't make a full tab stop
11264                if spaces_count > 0 {
11265                    reindented_line.extend(&space_cache[spaces_count - 1]);
11266                }
11267                // If we consume an extra character that was not indentation, add it back
11268                if let Some(extra_char) = first_non_indent_char {
11269                    reindented_line.push(extra_char);
11270                }
11271                // Append the rest of the line and replace old reference with new one
11272                reindented_line.extend(chars);
11273                *line = Cow::Owned(reindented_line.clone());
11274                reindented_line.clear();
11275            }
11276        });
11277    }
11278
11279    pub fn convert_to_upper_case(
11280        &mut self,
11281        _: &ConvertToUpperCase,
11282        window: &mut Window,
11283        cx: &mut Context<Self>,
11284    ) {
11285        self.manipulate_text(window, cx, |text| text.to_uppercase())
11286    }
11287
11288    pub fn convert_to_lower_case(
11289        &mut self,
11290        _: &ConvertToLowerCase,
11291        window: &mut Window,
11292        cx: &mut Context<Self>,
11293    ) {
11294        self.manipulate_text(window, cx, |text| text.to_lowercase())
11295    }
11296
11297    pub fn convert_to_title_case(
11298        &mut self,
11299        _: &ConvertToTitleCase,
11300        window: &mut Window,
11301        cx: &mut Context<Self>,
11302    ) {
11303        self.manipulate_text(window, cx, |text| {
11304            text.split('\n')
11305                .map(|line| line.to_case(Case::Title))
11306                .join("\n")
11307        })
11308    }
11309
11310    pub fn convert_to_snake_case(
11311        &mut self,
11312        _: &ConvertToSnakeCase,
11313        window: &mut Window,
11314        cx: &mut Context<Self>,
11315    ) {
11316        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11317    }
11318
11319    pub fn convert_to_kebab_case(
11320        &mut self,
11321        _: &ConvertToKebabCase,
11322        window: &mut Window,
11323        cx: &mut Context<Self>,
11324    ) {
11325        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11326    }
11327
11328    pub fn convert_to_upper_camel_case(
11329        &mut self,
11330        _: &ConvertToUpperCamelCase,
11331        window: &mut Window,
11332        cx: &mut Context<Self>,
11333    ) {
11334        self.manipulate_text(window, cx, |text| {
11335            text.split('\n')
11336                .map(|line| line.to_case(Case::UpperCamel))
11337                .join("\n")
11338        })
11339    }
11340
11341    pub fn convert_to_lower_camel_case(
11342        &mut self,
11343        _: &ConvertToLowerCamelCase,
11344        window: &mut Window,
11345        cx: &mut Context<Self>,
11346    ) {
11347        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11348    }
11349
11350    pub fn convert_to_opposite_case(
11351        &mut self,
11352        _: &ConvertToOppositeCase,
11353        window: &mut Window,
11354        cx: &mut Context<Self>,
11355    ) {
11356        self.manipulate_text(window, cx, |text| {
11357            text.chars()
11358                .fold(String::with_capacity(text.len()), |mut t, c| {
11359                    if c.is_uppercase() {
11360                        t.extend(c.to_lowercase());
11361                    } else {
11362                        t.extend(c.to_uppercase());
11363                    }
11364                    t
11365                })
11366        })
11367    }
11368
11369    pub fn convert_to_sentence_case(
11370        &mut self,
11371        _: &ConvertToSentenceCase,
11372        window: &mut Window,
11373        cx: &mut Context<Self>,
11374    ) {
11375        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11376    }
11377
11378    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11379        self.manipulate_text(window, cx, |text| {
11380            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11381            if has_upper_case_characters {
11382                text.to_lowercase()
11383            } else {
11384                text.to_uppercase()
11385            }
11386        })
11387    }
11388
11389    pub fn convert_to_rot13(
11390        &mut self,
11391        _: &ConvertToRot13,
11392        window: &mut Window,
11393        cx: &mut Context<Self>,
11394    ) {
11395        self.manipulate_text(window, cx, |text| {
11396            text.chars()
11397                .map(|c| match c {
11398                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11399                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11400                    _ => c,
11401                })
11402                .collect()
11403        })
11404    }
11405
11406    pub fn convert_to_rot47(
11407        &mut self,
11408        _: &ConvertToRot47,
11409        window: &mut Window,
11410        cx: &mut Context<Self>,
11411    ) {
11412        self.manipulate_text(window, cx, |text| {
11413            text.chars()
11414                .map(|c| {
11415                    let code_point = c as u32;
11416                    if code_point >= 33 && code_point <= 126 {
11417                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11418                    }
11419                    c
11420                })
11421                .collect()
11422        })
11423    }
11424
11425    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11426    where
11427        Fn: FnMut(&str) -> String,
11428    {
11429        let buffer = self.buffer.read(cx).snapshot(cx);
11430
11431        let mut new_selections = Vec::new();
11432        let mut edits = Vec::new();
11433        let mut selection_adjustment = 0i32;
11434
11435        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11436            let selection_is_empty = selection.is_empty();
11437
11438            let (start, end) = if selection_is_empty {
11439                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11440                (word_range.start, word_range.end)
11441            } else {
11442                (
11443                    buffer.point_to_offset(selection.start),
11444                    buffer.point_to_offset(selection.end),
11445                )
11446            };
11447
11448            let text = buffer.text_for_range(start..end).collect::<String>();
11449            let old_length = text.len() as i32;
11450            let text = callback(&text);
11451
11452            new_selections.push(Selection {
11453                start: (start as i32 - selection_adjustment) as usize,
11454                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11455                goal: SelectionGoal::None,
11456                id: selection.id,
11457                reversed: selection.reversed,
11458            });
11459
11460            selection_adjustment += old_length - text.len() as i32;
11461
11462            edits.push((start..end, text));
11463        }
11464
11465        self.transact(window, cx, |this, window, cx| {
11466            this.buffer.update(cx, |buffer, cx| {
11467                buffer.edit(edits, None, cx);
11468            });
11469
11470            this.change_selections(Default::default(), window, cx, |s| {
11471                s.select(new_selections);
11472            });
11473
11474            this.request_autoscroll(Autoscroll::fit(), cx);
11475        });
11476    }
11477
11478    pub fn move_selection_on_drop(
11479        &mut self,
11480        selection: &Selection<Anchor>,
11481        target: DisplayPoint,
11482        is_cut: bool,
11483        window: &mut Window,
11484        cx: &mut Context<Self>,
11485    ) {
11486        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11487        let buffer = display_map.buffer_snapshot();
11488        let mut edits = Vec::new();
11489        let insert_point = display_map
11490            .clip_point(target, Bias::Left)
11491            .to_point(&display_map);
11492        let text = buffer
11493            .text_for_range(selection.start..selection.end)
11494            .collect::<String>();
11495        if is_cut {
11496            edits.push(((selection.start..selection.end), String::new()));
11497        }
11498        let insert_anchor = buffer.anchor_before(insert_point);
11499        edits.push(((insert_anchor..insert_anchor), text));
11500        let last_edit_start = insert_anchor.bias_left(buffer);
11501        let last_edit_end = insert_anchor.bias_right(buffer);
11502        self.transact(window, cx, |this, window, cx| {
11503            this.buffer.update(cx, |buffer, cx| {
11504                buffer.edit(edits, None, cx);
11505            });
11506            this.change_selections(Default::default(), window, cx, |s| {
11507                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11508            });
11509        });
11510    }
11511
11512    pub fn clear_selection_drag_state(&mut self) {
11513        self.selection_drag_state = SelectionDragState::None;
11514    }
11515
11516    pub fn duplicate(
11517        &mut self,
11518        upwards: bool,
11519        whole_lines: bool,
11520        window: &mut Window,
11521        cx: &mut Context<Self>,
11522    ) {
11523        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11524
11525        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11526        let buffer = display_map.buffer_snapshot();
11527        let selections = self.selections.all::<Point>(&display_map);
11528
11529        let mut edits = Vec::new();
11530        let mut selections_iter = selections.iter().peekable();
11531        while let Some(selection) = selections_iter.next() {
11532            let mut rows = selection.spanned_rows(false, &display_map);
11533            // duplicate line-wise
11534            if whole_lines || selection.start == selection.end {
11535                // Avoid duplicating the same lines twice.
11536                while let Some(next_selection) = selections_iter.peek() {
11537                    let next_rows = next_selection.spanned_rows(false, &display_map);
11538                    if next_rows.start < rows.end {
11539                        rows.end = next_rows.end;
11540                        selections_iter.next().unwrap();
11541                    } else {
11542                        break;
11543                    }
11544                }
11545
11546                // Copy the text from the selected row region and splice it either at the start
11547                // or end of the region.
11548                let start = Point::new(rows.start.0, 0);
11549                let end = Point::new(
11550                    rows.end.previous_row().0,
11551                    buffer.line_len(rows.end.previous_row()),
11552                );
11553
11554                let mut text = buffer.text_for_range(start..end).collect::<String>();
11555
11556                let insert_location = if upwards {
11557                    // When duplicating upward, we need to insert before the current line.
11558                    // If we're on the last line and it doesn't end with a newline,
11559                    // we need to add a newline before the duplicated content.
11560                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11561                        && buffer.max_point().column > 0
11562                        && !text.ends_with('\n');
11563
11564                    if needs_leading_newline {
11565                        text.insert(0, '\n');
11566                        end
11567                    } else {
11568                        text.push('\n');
11569                        Point::new(rows.start.0, 0)
11570                    }
11571                } else {
11572                    text.push('\n');
11573                    start
11574                };
11575                edits.push((insert_location..insert_location, text));
11576            } else {
11577                // duplicate character-wise
11578                let start = selection.start;
11579                let end = selection.end;
11580                let text = buffer.text_for_range(start..end).collect::<String>();
11581                edits.push((selection.end..selection.end, text));
11582            }
11583        }
11584
11585        self.transact(window, cx, |this, window, cx| {
11586            this.buffer.update(cx, |buffer, cx| {
11587                buffer.edit(edits, None, cx);
11588            });
11589
11590            // When duplicating upward with whole lines, move the cursor to the duplicated line
11591            if upwards && whole_lines {
11592                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11593
11594                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11595                    let mut new_ranges = Vec::new();
11596                    let selections = s.all::<Point>(&display_map);
11597                    let mut selections_iter = selections.iter().peekable();
11598
11599                    while let Some(first_selection) = selections_iter.next() {
11600                        // Group contiguous selections together to find the total row span
11601                        let mut group_selections = vec![first_selection];
11602                        let mut rows = first_selection.spanned_rows(false, &display_map);
11603
11604                        while let Some(next_selection) = selections_iter.peek() {
11605                            let next_rows = next_selection.spanned_rows(false, &display_map);
11606                            if next_rows.start < rows.end {
11607                                rows.end = next_rows.end;
11608                                group_selections.push(selections_iter.next().unwrap());
11609                            } else {
11610                                break;
11611                            }
11612                        }
11613
11614                        let row_count = rows.end.0 - rows.start.0;
11615
11616                        // Move all selections in this group up by the total number of duplicated rows
11617                        for selection in group_selections {
11618                            let new_start = Point::new(
11619                                selection.start.row.saturating_sub(row_count),
11620                                selection.start.column,
11621                            );
11622
11623                            let new_end = Point::new(
11624                                selection.end.row.saturating_sub(row_count),
11625                                selection.end.column,
11626                            );
11627
11628                            new_ranges.push(new_start..new_end);
11629                        }
11630                    }
11631
11632                    s.select_ranges(new_ranges);
11633                });
11634            }
11635
11636            this.request_autoscroll(Autoscroll::fit(), cx);
11637        });
11638    }
11639
11640    pub fn duplicate_line_up(
11641        &mut self,
11642        _: &DuplicateLineUp,
11643        window: &mut Window,
11644        cx: &mut Context<Self>,
11645    ) {
11646        self.duplicate(true, true, window, cx);
11647    }
11648
11649    pub fn duplicate_line_down(
11650        &mut self,
11651        _: &DuplicateLineDown,
11652        window: &mut Window,
11653        cx: &mut Context<Self>,
11654    ) {
11655        self.duplicate(false, true, window, cx);
11656    }
11657
11658    pub fn duplicate_selection(
11659        &mut self,
11660        _: &DuplicateSelection,
11661        window: &mut Window,
11662        cx: &mut Context<Self>,
11663    ) {
11664        self.duplicate(false, false, window, cx);
11665    }
11666
11667    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11668        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11669        if self.mode.is_single_line() {
11670            cx.propagate();
11671            return;
11672        }
11673
11674        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11675        let buffer = self.buffer.read(cx).snapshot(cx);
11676
11677        let mut edits = Vec::new();
11678        let mut unfold_ranges = Vec::new();
11679        let mut refold_creases = Vec::new();
11680
11681        let selections = self.selections.all::<Point>(&display_map);
11682        let mut selections = selections.iter().peekable();
11683        let mut contiguous_row_selections = Vec::new();
11684        let mut new_selections = Vec::new();
11685
11686        while let Some(selection) = selections.next() {
11687            // Find all the selections that span a contiguous row range
11688            let (start_row, end_row) = consume_contiguous_rows(
11689                &mut contiguous_row_selections,
11690                selection,
11691                &display_map,
11692                &mut selections,
11693            );
11694
11695            // Move the text spanned by the row range to be before the line preceding the row range
11696            if start_row.0 > 0 {
11697                let range_to_move = Point::new(
11698                    start_row.previous_row().0,
11699                    buffer.line_len(start_row.previous_row()),
11700                )
11701                    ..Point::new(
11702                        end_row.previous_row().0,
11703                        buffer.line_len(end_row.previous_row()),
11704                    );
11705                let insertion_point = display_map
11706                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11707                    .0;
11708
11709                // Don't move lines across excerpts
11710                if buffer
11711                    .excerpt_containing(insertion_point..range_to_move.end)
11712                    .is_some()
11713                {
11714                    let text = buffer
11715                        .text_for_range(range_to_move.clone())
11716                        .flat_map(|s| s.chars())
11717                        .skip(1)
11718                        .chain(['\n'])
11719                        .collect::<String>();
11720
11721                    edits.push((
11722                        buffer.anchor_after(range_to_move.start)
11723                            ..buffer.anchor_before(range_to_move.end),
11724                        String::new(),
11725                    ));
11726                    let insertion_anchor = buffer.anchor_after(insertion_point);
11727                    edits.push((insertion_anchor..insertion_anchor, text));
11728
11729                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11730
11731                    // Move selections up
11732                    new_selections.extend(contiguous_row_selections.drain(..).map(
11733                        |mut selection| {
11734                            selection.start.row -= row_delta;
11735                            selection.end.row -= row_delta;
11736                            selection
11737                        },
11738                    ));
11739
11740                    // Move folds up
11741                    unfold_ranges.push(range_to_move.clone());
11742                    for fold in display_map.folds_in_range(
11743                        buffer.anchor_before(range_to_move.start)
11744                            ..buffer.anchor_after(range_to_move.end),
11745                    ) {
11746                        let mut start = fold.range.start.to_point(&buffer);
11747                        let mut end = fold.range.end.to_point(&buffer);
11748                        start.row -= row_delta;
11749                        end.row -= row_delta;
11750                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11751                    }
11752                }
11753            }
11754
11755            // If we didn't move line(s), preserve the existing selections
11756            new_selections.append(&mut contiguous_row_selections);
11757        }
11758
11759        self.transact(window, cx, |this, window, cx| {
11760            this.unfold_ranges(&unfold_ranges, true, true, cx);
11761            this.buffer.update(cx, |buffer, cx| {
11762                for (range, text) in edits {
11763                    buffer.edit([(range, text)], None, cx);
11764                }
11765            });
11766            this.fold_creases(refold_creases, true, window, cx);
11767            this.change_selections(Default::default(), window, cx, |s| {
11768                s.select(new_selections);
11769            })
11770        });
11771    }
11772
11773    pub fn move_line_down(
11774        &mut self,
11775        _: &MoveLineDown,
11776        window: &mut Window,
11777        cx: &mut Context<Self>,
11778    ) {
11779        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11780        if self.mode.is_single_line() {
11781            cx.propagate();
11782            return;
11783        }
11784
11785        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11786        let buffer = self.buffer.read(cx).snapshot(cx);
11787
11788        let mut edits = Vec::new();
11789        let mut unfold_ranges = Vec::new();
11790        let mut refold_creases = Vec::new();
11791
11792        let selections = self.selections.all::<Point>(&display_map);
11793        let mut selections = selections.iter().peekable();
11794        let mut contiguous_row_selections = Vec::new();
11795        let mut new_selections = Vec::new();
11796
11797        while let Some(selection) = selections.next() {
11798            // Find all the selections that span a contiguous row range
11799            let (start_row, end_row) = consume_contiguous_rows(
11800                &mut contiguous_row_selections,
11801                selection,
11802                &display_map,
11803                &mut selections,
11804            );
11805
11806            // Move the text spanned by the row range to be after the last line of the row range
11807            if end_row.0 <= buffer.max_point().row {
11808                let range_to_move =
11809                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11810                let insertion_point = display_map
11811                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11812                    .0;
11813
11814                // Don't move lines across excerpt boundaries
11815                if buffer
11816                    .excerpt_containing(range_to_move.start..insertion_point)
11817                    .is_some()
11818                {
11819                    let mut text = String::from("\n");
11820                    text.extend(buffer.text_for_range(range_to_move.clone()));
11821                    text.pop(); // Drop trailing newline
11822                    edits.push((
11823                        buffer.anchor_after(range_to_move.start)
11824                            ..buffer.anchor_before(range_to_move.end),
11825                        String::new(),
11826                    ));
11827                    let insertion_anchor = buffer.anchor_after(insertion_point);
11828                    edits.push((insertion_anchor..insertion_anchor, text));
11829
11830                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11831
11832                    // Move selections down
11833                    new_selections.extend(contiguous_row_selections.drain(..).map(
11834                        |mut selection| {
11835                            selection.start.row += row_delta;
11836                            selection.end.row += row_delta;
11837                            selection
11838                        },
11839                    ));
11840
11841                    // Move folds down
11842                    unfold_ranges.push(range_to_move.clone());
11843                    for fold in display_map.folds_in_range(
11844                        buffer.anchor_before(range_to_move.start)
11845                            ..buffer.anchor_after(range_to_move.end),
11846                    ) {
11847                        let mut start = fold.range.start.to_point(&buffer);
11848                        let mut end = fold.range.end.to_point(&buffer);
11849                        start.row += row_delta;
11850                        end.row += row_delta;
11851                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11852                    }
11853                }
11854            }
11855
11856            // If we didn't move line(s), preserve the existing selections
11857            new_selections.append(&mut contiguous_row_selections);
11858        }
11859
11860        self.transact(window, cx, |this, window, cx| {
11861            this.unfold_ranges(&unfold_ranges, true, true, cx);
11862            this.buffer.update(cx, |buffer, cx| {
11863                for (range, text) in edits {
11864                    buffer.edit([(range, text)], None, cx);
11865                }
11866            });
11867            this.fold_creases(refold_creases, true, window, cx);
11868            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11869        });
11870    }
11871
11872    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11873        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11874        let text_layout_details = &self.text_layout_details(window);
11875        self.transact(window, cx, |this, window, cx| {
11876            let edits = this.change_selections(Default::default(), window, cx, |s| {
11877                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11878                s.move_with(|display_map, selection| {
11879                    if !selection.is_empty() {
11880                        return;
11881                    }
11882
11883                    let mut head = selection.head();
11884                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11885                    if head.column() == display_map.line_len(head.row()) {
11886                        transpose_offset = display_map
11887                            .buffer_snapshot()
11888                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11889                    }
11890
11891                    if transpose_offset == 0 {
11892                        return;
11893                    }
11894
11895                    *head.column_mut() += 1;
11896                    head = display_map.clip_point(head, Bias::Right);
11897                    let goal = SelectionGoal::HorizontalPosition(
11898                        display_map
11899                            .x_for_display_point(head, text_layout_details)
11900                            .into(),
11901                    );
11902                    selection.collapse_to(head, goal);
11903
11904                    let transpose_start = display_map
11905                        .buffer_snapshot()
11906                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11907                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11908                        let transpose_end = display_map
11909                            .buffer_snapshot()
11910                            .clip_offset(transpose_offset + 1, Bias::Right);
11911                        if let Some(ch) = display_map
11912                            .buffer_snapshot()
11913                            .chars_at(transpose_start)
11914                            .next()
11915                        {
11916                            edits.push((transpose_start..transpose_offset, String::new()));
11917                            edits.push((transpose_end..transpose_end, ch.to_string()));
11918                        }
11919                    }
11920                });
11921                edits
11922            });
11923            this.buffer
11924                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11925            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
11926            this.change_selections(Default::default(), window, cx, |s| {
11927                s.select(selections);
11928            });
11929        });
11930    }
11931
11932    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11933        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11934        if self.mode.is_single_line() {
11935            cx.propagate();
11936            return;
11937        }
11938
11939        self.rewrap_impl(RewrapOptions::default(), cx)
11940    }
11941
11942    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11943        let buffer = self.buffer.read(cx).snapshot(cx);
11944        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11945
11946        #[derive(Clone, Debug, PartialEq)]
11947        enum CommentFormat {
11948            /// single line comment, with prefix for line
11949            Line(String),
11950            /// single line within a block comment, with prefix for line
11951            BlockLine(String),
11952            /// a single line of a block comment that includes the initial delimiter
11953            BlockCommentWithStart(BlockCommentConfig),
11954            /// a single line of a block comment that includes the ending delimiter
11955            BlockCommentWithEnd(BlockCommentConfig),
11956        }
11957
11958        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11959        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11960            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11961                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11962                .peekable();
11963
11964            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11965                row
11966            } else {
11967                return Vec::new();
11968            };
11969
11970            let language_settings = buffer.language_settings_at(selection.head(), cx);
11971            let language_scope = buffer.language_scope_at(selection.head());
11972
11973            let indent_and_prefix_for_row =
11974                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11975                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11976                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11977                        &language_scope
11978                    {
11979                        let indent_end = Point::new(row, indent.len);
11980                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11981                        let line_text_after_indent = buffer
11982                            .text_for_range(indent_end..line_end)
11983                            .collect::<String>();
11984
11985                        let is_within_comment_override = buffer
11986                            .language_scope_at(indent_end)
11987                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11988                        let comment_delimiters = if is_within_comment_override {
11989                            // we are within a comment syntax node, but we don't
11990                            // yet know what kind of comment: block, doc or line
11991                            match (
11992                                language_scope.documentation_comment(),
11993                                language_scope.block_comment(),
11994                            ) {
11995                                (Some(config), _) | (_, Some(config))
11996                                    if buffer.contains_str_at(indent_end, &config.start) =>
11997                                {
11998                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11999                                }
12000                                (Some(config), _) | (_, Some(config))
12001                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12002                                {
12003                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12004                                }
12005                                (Some(config), _) | (_, Some(config))
12006                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12007                                {
12008                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12009                                }
12010                                (_, _) => language_scope
12011                                    .line_comment_prefixes()
12012                                    .iter()
12013                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12014                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12015                            }
12016                        } else {
12017                            // we not in an overridden comment node, but we may
12018                            // be within a non-overridden line comment node
12019                            language_scope
12020                                .line_comment_prefixes()
12021                                .iter()
12022                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12023                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12024                        };
12025
12026                        let rewrap_prefix = language_scope
12027                            .rewrap_prefixes()
12028                            .iter()
12029                            .find_map(|prefix_regex| {
12030                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12031                                    if mat.start() == 0 {
12032                                        Some(mat.as_str().to_string())
12033                                    } else {
12034                                        None
12035                                    }
12036                                })
12037                            })
12038                            .flatten();
12039                        (comment_delimiters, rewrap_prefix)
12040                    } else {
12041                        (None, None)
12042                    };
12043                    (indent, comment_prefix, rewrap_prefix)
12044                };
12045
12046            let mut ranges = Vec::new();
12047            let from_empty_selection = selection.is_empty();
12048
12049            let mut current_range_start = first_row;
12050            let mut prev_row = first_row;
12051            let (
12052                mut current_range_indent,
12053                mut current_range_comment_delimiters,
12054                mut current_range_rewrap_prefix,
12055            ) = indent_and_prefix_for_row(first_row);
12056
12057            for row in non_blank_rows_iter.skip(1) {
12058                let has_paragraph_break = row > prev_row + 1;
12059
12060                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12061                    indent_and_prefix_for_row(row);
12062
12063                let has_indent_change = row_indent != current_range_indent;
12064                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12065
12066                let has_boundary_change = has_comment_change
12067                    || row_rewrap_prefix.is_some()
12068                    || (has_indent_change && current_range_comment_delimiters.is_some());
12069
12070                if has_paragraph_break || has_boundary_change {
12071                    ranges.push((
12072                        language_settings.clone(),
12073                        Point::new(current_range_start, 0)
12074                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12075                        current_range_indent,
12076                        current_range_comment_delimiters.clone(),
12077                        current_range_rewrap_prefix.clone(),
12078                        from_empty_selection,
12079                    ));
12080                    current_range_start = row;
12081                    current_range_indent = row_indent;
12082                    current_range_comment_delimiters = row_comment_delimiters;
12083                    current_range_rewrap_prefix = row_rewrap_prefix;
12084                }
12085                prev_row = row;
12086            }
12087
12088            ranges.push((
12089                language_settings.clone(),
12090                Point::new(current_range_start, 0)
12091                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12092                current_range_indent,
12093                current_range_comment_delimiters,
12094                current_range_rewrap_prefix,
12095                from_empty_selection,
12096            ));
12097
12098            ranges
12099        });
12100
12101        let mut edits = Vec::new();
12102        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12103
12104        for (
12105            language_settings,
12106            wrap_range,
12107            mut indent_size,
12108            comment_prefix,
12109            rewrap_prefix,
12110            from_empty_selection,
12111        ) in wrap_ranges
12112        {
12113            let mut start_row = wrap_range.start.row;
12114            let mut end_row = wrap_range.end.row;
12115
12116            // Skip selections that overlap with a range that has already been rewrapped.
12117            let selection_range = start_row..end_row;
12118            if rewrapped_row_ranges
12119                .iter()
12120                .any(|range| range.overlaps(&selection_range))
12121            {
12122                continue;
12123            }
12124
12125            let tab_size = language_settings.tab_size;
12126
12127            let (line_prefix, inside_comment) = match &comment_prefix {
12128                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12129                    (Some(prefix.as_str()), true)
12130                }
12131                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12132                    (Some(prefix.as_ref()), true)
12133                }
12134                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12135                    start: _,
12136                    end: _,
12137                    prefix,
12138                    tab_size,
12139                })) => {
12140                    indent_size.len += tab_size;
12141                    (Some(prefix.as_ref()), true)
12142                }
12143                None => (None, false),
12144            };
12145            let indent_prefix = indent_size.chars().collect::<String>();
12146            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12147
12148            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12149                RewrapBehavior::InComments => inside_comment,
12150                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12151                RewrapBehavior::Anywhere => true,
12152            };
12153
12154            let should_rewrap = options.override_language_settings
12155                || allow_rewrap_based_on_language
12156                || self.hard_wrap.is_some();
12157            if !should_rewrap {
12158                continue;
12159            }
12160
12161            if from_empty_selection {
12162                'expand_upwards: while start_row > 0 {
12163                    let prev_row = start_row - 1;
12164                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12165                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12166                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12167                    {
12168                        start_row = prev_row;
12169                    } else {
12170                        break 'expand_upwards;
12171                    }
12172                }
12173
12174                'expand_downwards: while end_row < buffer.max_point().row {
12175                    let next_row = end_row + 1;
12176                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12177                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12178                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12179                    {
12180                        end_row = next_row;
12181                    } else {
12182                        break 'expand_downwards;
12183                    }
12184                }
12185            }
12186
12187            let start = Point::new(start_row, 0);
12188            let start_offset = ToOffset::to_offset(&start, &buffer);
12189            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12190            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12191            let mut first_line_delimiter = None;
12192            let mut last_line_delimiter = None;
12193            let Some(lines_without_prefixes) = selection_text
12194                .lines()
12195                .enumerate()
12196                .map(|(ix, line)| {
12197                    let line_trimmed = line.trim_start();
12198                    if rewrap_prefix.is_some() && ix > 0 {
12199                        Ok(line_trimmed)
12200                    } else if let Some(
12201                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12202                            start,
12203                            prefix,
12204                            end,
12205                            tab_size,
12206                        })
12207                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12208                            start,
12209                            prefix,
12210                            end,
12211                            tab_size,
12212                        }),
12213                    ) = &comment_prefix
12214                    {
12215                        let line_trimmed = line_trimmed
12216                            .strip_prefix(start.as_ref())
12217                            .map(|s| {
12218                                let mut indent_size = indent_size;
12219                                indent_size.len -= tab_size;
12220                                let indent_prefix: String = indent_size.chars().collect();
12221                                first_line_delimiter = Some((indent_prefix, start));
12222                                s.trim_start()
12223                            })
12224                            .unwrap_or(line_trimmed);
12225                        let line_trimmed = line_trimmed
12226                            .strip_suffix(end.as_ref())
12227                            .map(|s| {
12228                                last_line_delimiter = Some(end);
12229                                s.trim_end()
12230                            })
12231                            .unwrap_or(line_trimmed);
12232                        let line_trimmed = line_trimmed
12233                            .strip_prefix(prefix.as_ref())
12234                            .unwrap_or(line_trimmed);
12235                        Ok(line_trimmed)
12236                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12237                        line_trimmed.strip_prefix(prefix).with_context(|| {
12238                            format!("line did not start with prefix {prefix:?}: {line:?}")
12239                        })
12240                    } else {
12241                        line_trimmed
12242                            .strip_prefix(&line_prefix.trim_start())
12243                            .with_context(|| {
12244                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12245                            })
12246                    }
12247                })
12248                .collect::<Result<Vec<_>, _>>()
12249                .log_err()
12250            else {
12251                continue;
12252            };
12253
12254            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12255                buffer
12256                    .language_settings_at(Point::new(start_row, 0), cx)
12257                    .preferred_line_length as usize
12258            });
12259
12260            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12261                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12262            } else {
12263                line_prefix.clone()
12264            };
12265
12266            let wrapped_text = {
12267                let mut wrapped_text = wrap_with_prefix(
12268                    line_prefix,
12269                    subsequent_lines_prefix,
12270                    lines_without_prefixes.join("\n"),
12271                    wrap_column,
12272                    tab_size,
12273                    options.preserve_existing_whitespace,
12274                );
12275
12276                if let Some((indent, delimiter)) = first_line_delimiter {
12277                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12278                }
12279                if let Some(last_line) = last_line_delimiter {
12280                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12281                }
12282
12283                wrapped_text
12284            };
12285
12286            // TODO: should always use char-based diff while still supporting cursor behavior that
12287            // matches vim.
12288            let mut diff_options = DiffOptions::default();
12289            if options.override_language_settings {
12290                diff_options.max_word_diff_len = 0;
12291                diff_options.max_word_diff_line_count = 0;
12292            } else {
12293                diff_options.max_word_diff_len = usize::MAX;
12294                diff_options.max_word_diff_line_count = usize::MAX;
12295            }
12296
12297            for (old_range, new_text) in
12298                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12299            {
12300                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12301                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12302                edits.push((edit_start..edit_end, new_text));
12303            }
12304
12305            rewrapped_row_ranges.push(start_row..=end_row);
12306        }
12307
12308        self.buffer
12309            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12310    }
12311
12312    pub fn cut_common(
12313        &mut self,
12314        cut_no_selection_line: bool,
12315        window: &mut Window,
12316        cx: &mut Context<Self>,
12317    ) -> ClipboardItem {
12318        let mut text = String::new();
12319        let buffer = self.buffer.read(cx).snapshot(cx);
12320        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12321        let mut clipboard_selections = Vec::with_capacity(selections.len());
12322        {
12323            let max_point = buffer.max_point();
12324            let mut is_first = true;
12325            for selection in &mut selections {
12326                let is_entire_line =
12327                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12328                if is_entire_line {
12329                    selection.start = Point::new(selection.start.row, 0);
12330                    if !selection.is_empty() && selection.end.column == 0 {
12331                        selection.end = cmp::min(max_point, selection.end);
12332                    } else {
12333                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12334                    }
12335                    selection.goal = SelectionGoal::None;
12336                }
12337                if is_first {
12338                    is_first = false;
12339                } else {
12340                    text += "\n";
12341                }
12342                let mut len = 0;
12343                for chunk in buffer.text_for_range(selection.start..selection.end) {
12344                    text.push_str(chunk);
12345                    len += chunk.len();
12346                }
12347                clipboard_selections.push(ClipboardSelection {
12348                    len,
12349                    is_entire_line,
12350                    first_line_indent: buffer
12351                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12352                        .len,
12353                });
12354            }
12355        }
12356
12357        self.transact(window, cx, |this, window, cx| {
12358            this.change_selections(Default::default(), window, cx, |s| {
12359                s.select(selections);
12360            });
12361            this.insert("", window, cx);
12362        });
12363        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12364    }
12365
12366    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12367        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12368        let item = self.cut_common(true, window, cx);
12369        cx.write_to_clipboard(item);
12370    }
12371
12372    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12373        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12374        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12375            s.move_with(|snapshot, sel| {
12376                if sel.is_empty() {
12377                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12378                }
12379                if sel.is_empty() {
12380                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12381                }
12382            });
12383        });
12384        let item = self.cut_common(false, window, cx);
12385        cx.set_global(KillRing(item))
12386    }
12387
12388    pub fn kill_ring_yank(
12389        &mut self,
12390        _: &KillRingYank,
12391        window: &mut Window,
12392        cx: &mut Context<Self>,
12393    ) {
12394        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12395        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12396            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12397                (kill_ring.text().to_string(), kill_ring.metadata_json())
12398            } else {
12399                return;
12400            }
12401        } else {
12402            return;
12403        };
12404        self.do_paste(&text, metadata, false, window, cx);
12405    }
12406
12407    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12408        self.do_copy(true, cx);
12409    }
12410
12411    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12412        self.do_copy(false, cx);
12413    }
12414
12415    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12416        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12417        let buffer = self.buffer.read(cx).read(cx);
12418        let mut text = String::new();
12419
12420        let mut clipboard_selections = Vec::with_capacity(selections.len());
12421        {
12422            let max_point = buffer.max_point();
12423            let mut is_first = true;
12424            for selection in &selections {
12425                let mut start = selection.start;
12426                let mut end = selection.end;
12427                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12428                let mut add_trailing_newline = false;
12429                if is_entire_line {
12430                    start = Point::new(start.row, 0);
12431                    let next_line_start = Point::new(end.row + 1, 0);
12432                    if next_line_start <= max_point {
12433                        end = next_line_start;
12434                    } else {
12435                        // We're on the last line without a trailing newline.
12436                        // Copy to the end of the line and add a newline afterwards.
12437                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12438                        add_trailing_newline = true;
12439                    }
12440                }
12441
12442                let mut trimmed_selections = Vec::new();
12443                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12444                    let row = MultiBufferRow(start.row);
12445                    let first_indent = buffer.indent_size_for_line(row);
12446                    if first_indent.len == 0 || start.column > first_indent.len {
12447                        trimmed_selections.push(start..end);
12448                    } else {
12449                        trimmed_selections.push(
12450                            Point::new(row.0, first_indent.len)
12451                                ..Point::new(row.0, buffer.line_len(row)),
12452                        );
12453                        for row in start.row + 1..=end.row {
12454                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12455                            if row == end.row {
12456                                line_len = end.column;
12457                            }
12458                            if line_len == 0 {
12459                                trimmed_selections
12460                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12461                                continue;
12462                            }
12463                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12464                            if row_indent_size.len >= first_indent.len {
12465                                trimmed_selections.push(
12466                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12467                                );
12468                            } else {
12469                                trimmed_selections.clear();
12470                                trimmed_selections.push(start..end);
12471                                break;
12472                            }
12473                        }
12474                    }
12475                } else {
12476                    trimmed_selections.push(start..end);
12477                }
12478
12479                for trimmed_range in trimmed_selections {
12480                    if is_first {
12481                        is_first = false;
12482                    } else {
12483                        text += "\n";
12484                    }
12485                    let mut len = 0;
12486                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12487                        text.push_str(chunk);
12488                        len += chunk.len();
12489                    }
12490                    if add_trailing_newline {
12491                        text.push('\n');
12492                        len += 1;
12493                    }
12494                    clipboard_selections.push(ClipboardSelection {
12495                        len,
12496                        is_entire_line,
12497                        first_line_indent: buffer
12498                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12499                            .len,
12500                    });
12501                }
12502            }
12503        }
12504
12505        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12506            text,
12507            clipboard_selections,
12508        ));
12509    }
12510
12511    pub fn do_paste(
12512        &mut self,
12513        text: &String,
12514        clipboard_selections: Option<Vec<ClipboardSelection>>,
12515        handle_entire_lines: bool,
12516        window: &mut Window,
12517        cx: &mut Context<Self>,
12518    ) {
12519        if self.read_only(cx) {
12520            return;
12521        }
12522
12523        let clipboard_text = Cow::Borrowed(text.as_str());
12524
12525        self.transact(window, cx, |this, window, cx| {
12526            let had_active_edit_prediction = this.has_active_edit_prediction();
12527            let display_map = this.display_snapshot(cx);
12528            let old_selections = this.selections.all::<usize>(&display_map);
12529            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12530
12531            if let Some(mut clipboard_selections) = clipboard_selections {
12532                let all_selections_were_entire_line =
12533                    clipboard_selections.iter().all(|s| s.is_entire_line);
12534                let first_selection_indent_column =
12535                    clipboard_selections.first().map(|s| s.first_line_indent);
12536                if clipboard_selections.len() != old_selections.len() {
12537                    clipboard_selections.drain(..);
12538                }
12539                let mut auto_indent_on_paste = true;
12540
12541                this.buffer.update(cx, |buffer, cx| {
12542                    let snapshot = buffer.read(cx);
12543                    auto_indent_on_paste = snapshot
12544                        .language_settings_at(cursor_offset, cx)
12545                        .auto_indent_on_paste;
12546
12547                    let mut start_offset = 0;
12548                    let mut edits = Vec::new();
12549                    let mut original_indent_columns = Vec::new();
12550                    for (ix, selection) in old_selections.iter().enumerate() {
12551                        let to_insert;
12552                        let entire_line;
12553                        let original_indent_column;
12554                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12555                            let end_offset = start_offset + clipboard_selection.len;
12556                            to_insert = &clipboard_text[start_offset..end_offset];
12557                            entire_line = clipboard_selection.is_entire_line;
12558                            start_offset = end_offset + 1;
12559                            original_indent_column = Some(clipboard_selection.first_line_indent);
12560                        } else {
12561                            to_insert = &*clipboard_text;
12562                            entire_line = all_selections_were_entire_line;
12563                            original_indent_column = first_selection_indent_column
12564                        }
12565
12566                        let (range, to_insert) =
12567                            if selection.is_empty() && handle_entire_lines && entire_line {
12568                                // If the corresponding selection was empty when this slice of the
12569                                // clipboard text was written, then the entire line containing the
12570                                // selection was copied. If this selection is also currently empty,
12571                                // then paste the line before the current line of the buffer.
12572                                let column = selection.start.to_point(&snapshot).column as usize;
12573                                let line_start = selection.start - column;
12574                                (line_start..line_start, Cow::Borrowed(to_insert))
12575                            } else {
12576                                let language = snapshot.language_at(selection.head());
12577                                let range = selection.range();
12578                                if let Some(language) = language
12579                                    && language.name() == "Markdown".into()
12580                                {
12581                                    edit_for_markdown_paste(
12582                                        &snapshot,
12583                                        range,
12584                                        to_insert,
12585                                        url::Url::parse(to_insert).ok(),
12586                                    )
12587                                } else {
12588                                    (range, Cow::Borrowed(to_insert))
12589                                }
12590                            };
12591
12592                        edits.push((range, to_insert));
12593                        original_indent_columns.push(original_indent_column);
12594                    }
12595                    drop(snapshot);
12596
12597                    buffer.edit(
12598                        edits,
12599                        if auto_indent_on_paste {
12600                            Some(AutoindentMode::Block {
12601                                original_indent_columns,
12602                            })
12603                        } else {
12604                            None
12605                        },
12606                        cx,
12607                    );
12608                });
12609
12610                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12611                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12612            } else {
12613                let url = url::Url::parse(&clipboard_text).ok();
12614
12615                let auto_indent_mode = if !clipboard_text.is_empty() {
12616                    Some(AutoindentMode::Block {
12617                        original_indent_columns: Vec::new(),
12618                    })
12619                } else {
12620                    None
12621                };
12622
12623                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12624                    let snapshot = buffer.snapshot(cx);
12625
12626                    let anchors = old_selections
12627                        .iter()
12628                        .map(|s| {
12629                            let anchor = snapshot.anchor_after(s.head());
12630                            s.map(|_| anchor)
12631                        })
12632                        .collect::<Vec<_>>();
12633
12634                    let mut edits = Vec::new();
12635
12636                    for selection in old_selections.iter() {
12637                        let language = snapshot.language_at(selection.head());
12638                        let range = selection.range();
12639
12640                        let (edit_range, edit_text) = if let Some(language) = language
12641                            && language.name() == "Markdown".into()
12642                        {
12643                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12644                        } else {
12645                            (range, clipboard_text.clone())
12646                        };
12647
12648                        edits.push((edit_range, edit_text));
12649                    }
12650
12651                    drop(snapshot);
12652                    buffer.edit(edits, auto_indent_mode, cx);
12653
12654                    anchors
12655                });
12656
12657                this.change_selections(Default::default(), window, cx, |s| {
12658                    s.select_anchors(selection_anchors);
12659                });
12660            }
12661
12662            let trigger_in_words =
12663                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12664
12665            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12666        });
12667    }
12668
12669    pub fn diff_clipboard_with_selection(
12670        &mut self,
12671        _: &DiffClipboardWithSelection,
12672        window: &mut Window,
12673        cx: &mut Context<Self>,
12674    ) {
12675        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12676
12677        if selections.is_empty() {
12678            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12679            return;
12680        };
12681
12682        let clipboard_text = match cx.read_from_clipboard() {
12683            Some(item) => match item.entries().first() {
12684                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12685                _ => None,
12686            },
12687            None => None,
12688        };
12689
12690        let Some(clipboard_text) = clipboard_text else {
12691            log::warn!("Clipboard doesn't contain text.");
12692            return;
12693        };
12694
12695        window.dispatch_action(
12696            Box::new(DiffClipboardWithSelectionData {
12697                clipboard_text,
12698                editor: cx.entity(),
12699            }),
12700            cx,
12701        );
12702    }
12703
12704    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12705        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12706        if let Some(item) = cx.read_from_clipboard() {
12707            let entries = item.entries();
12708
12709            match entries.first() {
12710                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12711                // of all the pasted entries.
12712                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12713                    .do_paste(
12714                        clipboard_string.text(),
12715                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12716                        true,
12717                        window,
12718                        cx,
12719                    ),
12720                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12721            }
12722        }
12723    }
12724
12725    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12726        if self.read_only(cx) {
12727            return;
12728        }
12729
12730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12731
12732        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12733            if let Some((selections, _)) =
12734                self.selection_history.transaction(transaction_id).cloned()
12735            {
12736                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12737                    s.select_anchors(selections.to_vec());
12738                });
12739            } else {
12740                log::error!(
12741                    "No entry in selection_history found for undo. \
12742                     This may correspond to a bug where undo does not update the selection. \
12743                     If this is occurring, please add details to \
12744                     https://github.com/zed-industries/zed/issues/22692"
12745                );
12746            }
12747            self.request_autoscroll(Autoscroll::fit(), cx);
12748            self.unmark_text(window, cx);
12749            self.refresh_edit_prediction(true, false, window, cx);
12750            cx.emit(EditorEvent::Edited { transaction_id });
12751            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12752        }
12753    }
12754
12755    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12756        if self.read_only(cx) {
12757            return;
12758        }
12759
12760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12761
12762        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12763            if let Some((_, Some(selections))) =
12764                self.selection_history.transaction(transaction_id).cloned()
12765            {
12766                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12767                    s.select_anchors(selections.to_vec());
12768                });
12769            } else {
12770                log::error!(
12771                    "No entry in selection_history found for redo. \
12772                     This may correspond to a bug where undo does not update the selection. \
12773                     If this is occurring, please add details to \
12774                     https://github.com/zed-industries/zed/issues/22692"
12775                );
12776            }
12777            self.request_autoscroll(Autoscroll::fit(), cx);
12778            self.unmark_text(window, cx);
12779            self.refresh_edit_prediction(true, false, window, cx);
12780            cx.emit(EditorEvent::Edited { transaction_id });
12781        }
12782    }
12783
12784    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12785        self.buffer
12786            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12787    }
12788
12789    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12790        self.buffer
12791            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12792    }
12793
12794    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12795        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12796        self.change_selections(Default::default(), window, cx, |s| {
12797            s.move_with(|map, selection| {
12798                let cursor = if selection.is_empty() {
12799                    movement::left(map, selection.start)
12800                } else {
12801                    selection.start
12802                };
12803                selection.collapse_to(cursor, SelectionGoal::None);
12804            });
12805        })
12806    }
12807
12808    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12809        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12810        self.change_selections(Default::default(), window, cx, |s| {
12811            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12812        })
12813    }
12814
12815    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12816        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12817        self.change_selections(Default::default(), window, cx, |s| {
12818            s.move_with(|map, selection| {
12819                let cursor = if selection.is_empty() {
12820                    movement::right(map, selection.end)
12821                } else {
12822                    selection.end
12823                };
12824                selection.collapse_to(cursor, SelectionGoal::None)
12825            });
12826        })
12827    }
12828
12829    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12830        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12831        self.change_selections(Default::default(), window, cx, |s| {
12832            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12833        });
12834    }
12835
12836    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12837        if self.take_rename(true, window, cx).is_some() {
12838            return;
12839        }
12840
12841        if self.mode.is_single_line() {
12842            cx.propagate();
12843            return;
12844        }
12845
12846        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12847
12848        let text_layout_details = &self.text_layout_details(window);
12849        let selection_count = self.selections.count();
12850        let first_selection = self.selections.first_anchor();
12851
12852        self.change_selections(Default::default(), window, cx, |s| {
12853            s.move_with(|map, selection| {
12854                if !selection.is_empty() {
12855                    selection.goal = SelectionGoal::None;
12856                }
12857                let (cursor, goal) = movement::up(
12858                    map,
12859                    selection.start,
12860                    selection.goal,
12861                    false,
12862                    text_layout_details,
12863                );
12864                selection.collapse_to(cursor, goal);
12865            });
12866        });
12867
12868        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12869        {
12870            cx.propagate();
12871        }
12872    }
12873
12874    pub fn move_up_by_lines(
12875        &mut self,
12876        action: &MoveUpByLines,
12877        window: &mut Window,
12878        cx: &mut Context<Self>,
12879    ) {
12880        if self.take_rename(true, window, cx).is_some() {
12881            return;
12882        }
12883
12884        if self.mode.is_single_line() {
12885            cx.propagate();
12886            return;
12887        }
12888
12889        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12890
12891        let text_layout_details = &self.text_layout_details(window);
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_by_rows(
12899                    map,
12900                    selection.start,
12901                    action.lines,
12902                    selection.goal,
12903                    false,
12904                    text_layout_details,
12905                );
12906                selection.collapse_to(cursor, goal);
12907            });
12908        })
12909    }
12910
12911    pub fn move_down_by_lines(
12912        &mut self,
12913        action: &MoveDownByLines,
12914        window: &mut Window,
12915        cx: &mut Context<Self>,
12916    ) {
12917        if self.take_rename(true, window, cx).is_some() {
12918            return;
12919        }
12920
12921        if self.mode.is_single_line() {
12922            cx.propagate();
12923            return;
12924        }
12925
12926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12927
12928        let text_layout_details = &self.text_layout_details(window);
12929
12930        self.change_selections(Default::default(), window, cx, |s| {
12931            s.move_with(|map, selection| {
12932                if !selection.is_empty() {
12933                    selection.goal = SelectionGoal::None;
12934                }
12935                let (cursor, goal) = movement::down_by_rows(
12936                    map,
12937                    selection.start,
12938                    action.lines,
12939                    selection.goal,
12940                    false,
12941                    text_layout_details,
12942                );
12943                selection.collapse_to(cursor, goal);
12944            });
12945        })
12946    }
12947
12948    pub fn select_down_by_lines(
12949        &mut self,
12950        action: &SelectDownByLines,
12951        window: &mut Window,
12952        cx: &mut Context<Self>,
12953    ) {
12954        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12955        let text_layout_details = &self.text_layout_details(window);
12956        self.change_selections(Default::default(), window, cx, |s| {
12957            s.move_heads_with(|map, head, goal| {
12958                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12959            })
12960        })
12961    }
12962
12963    pub fn select_up_by_lines(
12964        &mut self,
12965        action: &SelectUpByLines,
12966        window: &mut Window,
12967        cx: &mut Context<Self>,
12968    ) {
12969        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12970        let text_layout_details = &self.text_layout_details(window);
12971        self.change_selections(Default::default(), window, cx, |s| {
12972            s.move_heads_with(|map, head, goal| {
12973                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12974            })
12975        })
12976    }
12977
12978    pub fn select_page_up(
12979        &mut self,
12980        _: &SelectPageUp,
12981        window: &mut Window,
12982        cx: &mut Context<Self>,
12983    ) {
12984        let Some(row_count) = self.visible_row_count() else {
12985            return;
12986        };
12987
12988        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12989
12990        let text_layout_details = &self.text_layout_details(window);
12991
12992        self.change_selections(Default::default(), window, cx, |s| {
12993            s.move_heads_with(|map, head, goal| {
12994                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12995            })
12996        })
12997    }
12998
12999    pub fn move_page_up(
13000        &mut self,
13001        action: &MovePageUp,
13002        window: &mut Window,
13003        cx: &mut Context<Self>,
13004    ) {
13005        if self.take_rename(true, window, cx).is_some() {
13006            return;
13007        }
13008
13009        if self
13010            .context_menu
13011            .borrow_mut()
13012            .as_mut()
13013            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13014            .unwrap_or(false)
13015        {
13016            return;
13017        }
13018
13019        if matches!(self.mode, EditorMode::SingleLine) {
13020            cx.propagate();
13021            return;
13022        }
13023
13024        let Some(row_count) = self.visible_row_count() else {
13025            return;
13026        };
13027
13028        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13029
13030        let effects = if action.center_cursor {
13031            SelectionEffects::scroll(Autoscroll::center())
13032        } else {
13033            SelectionEffects::default()
13034        };
13035
13036        let text_layout_details = &self.text_layout_details(window);
13037
13038        self.change_selections(effects, window, cx, |s| {
13039            s.move_with(|map, selection| {
13040                if !selection.is_empty() {
13041                    selection.goal = SelectionGoal::None;
13042                }
13043                let (cursor, goal) = movement::up_by_rows(
13044                    map,
13045                    selection.end,
13046                    row_count,
13047                    selection.goal,
13048                    false,
13049                    text_layout_details,
13050                );
13051                selection.collapse_to(cursor, goal);
13052            });
13053        });
13054    }
13055
13056    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13058        let text_layout_details = &self.text_layout_details(window);
13059        self.change_selections(Default::default(), window, cx, |s| {
13060            s.move_heads_with(|map, head, goal| {
13061                movement::up(map, head, goal, false, text_layout_details)
13062            })
13063        })
13064    }
13065
13066    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13067        self.take_rename(true, window, cx);
13068
13069        if self.mode.is_single_line() {
13070            cx.propagate();
13071            return;
13072        }
13073
13074        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13075
13076        let text_layout_details = &self.text_layout_details(window);
13077        let selection_count = self.selections.count();
13078        let first_selection = self.selections.first_anchor();
13079
13080        self.change_selections(Default::default(), window, cx, |s| {
13081            s.move_with(|map, selection| {
13082                if !selection.is_empty() {
13083                    selection.goal = SelectionGoal::None;
13084                }
13085                let (cursor, goal) = movement::down(
13086                    map,
13087                    selection.end,
13088                    selection.goal,
13089                    false,
13090                    text_layout_details,
13091                );
13092                selection.collapse_to(cursor, goal);
13093            });
13094        });
13095
13096        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13097        {
13098            cx.propagate();
13099        }
13100    }
13101
13102    pub fn select_page_down(
13103        &mut self,
13104        _: &SelectPageDown,
13105        window: &mut Window,
13106        cx: &mut Context<Self>,
13107    ) {
13108        let Some(row_count) = self.visible_row_count() else {
13109            return;
13110        };
13111
13112        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13113
13114        let text_layout_details = &self.text_layout_details(window);
13115
13116        self.change_selections(Default::default(), window, cx, |s| {
13117            s.move_heads_with(|map, head, goal| {
13118                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13119            })
13120        })
13121    }
13122
13123    pub fn move_page_down(
13124        &mut self,
13125        action: &MovePageDown,
13126        window: &mut Window,
13127        cx: &mut Context<Self>,
13128    ) {
13129        if self.take_rename(true, window, cx).is_some() {
13130            return;
13131        }
13132
13133        if self
13134            .context_menu
13135            .borrow_mut()
13136            .as_mut()
13137            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13138            .unwrap_or(false)
13139        {
13140            return;
13141        }
13142
13143        if matches!(self.mode, EditorMode::SingleLine) {
13144            cx.propagate();
13145            return;
13146        }
13147
13148        let Some(row_count) = self.visible_row_count() else {
13149            return;
13150        };
13151
13152        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13153
13154        let effects = if action.center_cursor {
13155            SelectionEffects::scroll(Autoscroll::center())
13156        } else {
13157            SelectionEffects::default()
13158        };
13159
13160        let text_layout_details = &self.text_layout_details(window);
13161        self.change_selections(effects, window, cx, |s| {
13162            s.move_with(|map, selection| {
13163                if !selection.is_empty() {
13164                    selection.goal = SelectionGoal::None;
13165                }
13166                let (cursor, goal) = movement::down_by_rows(
13167                    map,
13168                    selection.end,
13169                    row_count,
13170                    selection.goal,
13171                    false,
13172                    text_layout_details,
13173                );
13174                selection.collapse_to(cursor, goal);
13175            });
13176        });
13177    }
13178
13179    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13180        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13181        let text_layout_details = &self.text_layout_details(window);
13182        self.change_selections(Default::default(), window, cx, |s| {
13183            s.move_heads_with(|map, head, goal| {
13184                movement::down(map, head, goal, false, text_layout_details)
13185            })
13186        });
13187    }
13188
13189    pub fn context_menu_first(
13190        &mut self,
13191        _: &ContextMenuFirst,
13192        window: &mut Window,
13193        cx: &mut Context<Self>,
13194    ) {
13195        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13196            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13197        }
13198    }
13199
13200    pub fn context_menu_prev(
13201        &mut self,
13202        _: &ContextMenuPrevious,
13203        window: &mut Window,
13204        cx: &mut Context<Self>,
13205    ) {
13206        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13207            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13208        }
13209    }
13210
13211    pub fn context_menu_next(
13212        &mut self,
13213        _: &ContextMenuNext,
13214        window: &mut Window,
13215        cx: &mut Context<Self>,
13216    ) {
13217        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13218            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13219        }
13220    }
13221
13222    pub fn context_menu_last(
13223        &mut self,
13224        _: &ContextMenuLast,
13225        window: &mut Window,
13226        cx: &mut Context<Self>,
13227    ) {
13228        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13229            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13230        }
13231    }
13232
13233    pub fn signature_help_prev(
13234        &mut self,
13235        _: &SignatureHelpPrevious,
13236        _: &mut Window,
13237        cx: &mut Context<Self>,
13238    ) {
13239        if let Some(popover) = self.signature_help_state.popover_mut() {
13240            if popover.current_signature == 0 {
13241                popover.current_signature = popover.signatures.len() - 1;
13242            } else {
13243                popover.current_signature -= 1;
13244            }
13245            cx.notify();
13246        }
13247    }
13248
13249    pub fn signature_help_next(
13250        &mut self,
13251        _: &SignatureHelpNext,
13252        _: &mut Window,
13253        cx: &mut Context<Self>,
13254    ) {
13255        if let Some(popover) = self.signature_help_state.popover_mut() {
13256            if popover.current_signature + 1 == popover.signatures.len() {
13257                popover.current_signature = 0;
13258            } else {
13259                popover.current_signature += 1;
13260            }
13261            cx.notify();
13262        }
13263    }
13264
13265    pub fn move_to_previous_word_start(
13266        &mut self,
13267        _: &MoveToPreviousWordStart,
13268        window: &mut Window,
13269        cx: &mut Context<Self>,
13270    ) {
13271        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13272        self.change_selections(Default::default(), window, cx, |s| {
13273            s.move_cursors_with(|map, head, _| {
13274                (
13275                    movement::previous_word_start(map, head),
13276                    SelectionGoal::None,
13277                )
13278            });
13279        })
13280    }
13281
13282    pub fn move_to_previous_subword_start(
13283        &mut self,
13284        _: &MoveToPreviousSubwordStart,
13285        window: &mut Window,
13286        cx: &mut Context<Self>,
13287    ) {
13288        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13289        self.change_selections(Default::default(), window, cx, |s| {
13290            s.move_cursors_with(|map, head, _| {
13291                (
13292                    movement::previous_subword_start(map, head),
13293                    SelectionGoal::None,
13294                )
13295            });
13296        })
13297    }
13298
13299    pub fn select_to_previous_word_start(
13300        &mut self,
13301        _: &SelectToPreviousWordStart,
13302        window: &mut Window,
13303        cx: &mut Context<Self>,
13304    ) {
13305        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13306        self.change_selections(Default::default(), window, cx, |s| {
13307            s.move_heads_with(|map, head, _| {
13308                (
13309                    movement::previous_word_start(map, head),
13310                    SelectionGoal::None,
13311                )
13312            });
13313        })
13314    }
13315
13316    pub fn select_to_previous_subword_start(
13317        &mut self,
13318        _: &SelectToPreviousSubwordStart,
13319        window: &mut Window,
13320        cx: &mut Context<Self>,
13321    ) {
13322        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13323        self.change_selections(Default::default(), window, cx, |s| {
13324            s.move_heads_with(|map, head, _| {
13325                (
13326                    movement::previous_subword_start(map, head),
13327                    SelectionGoal::None,
13328                )
13329            });
13330        })
13331    }
13332
13333    pub fn delete_to_previous_word_start(
13334        &mut self,
13335        action: &DeleteToPreviousWordStart,
13336        window: &mut Window,
13337        cx: &mut Context<Self>,
13338    ) {
13339        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13340        self.transact(window, cx, |this, window, cx| {
13341            this.select_autoclose_pair(window, cx);
13342            this.change_selections(Default::default(), window, cx, |s| {
13343                s.move_with(|map, selection| {
13344                    if selection.is_empty() {
13345                        let mut cursor = if action.ignore_newlines {
13346                            movement::previous_word_start(map, selection.head())
13347                        } else {
13348                            movement::previous_word_start_or_newline(map, selection.head())
13349                        };
13350                        cursor = movement::adjust_greedy_deletion(
13351                            map,
13352                            selection.head(),
13353                            cursor,
13354                            action.ignore_brackets,
13355                        );
13356                        selection.set_head(cursor, SelectionGoal::None);
13357                    }
13358                });
13359            });
13360            this.insert("", window, cx);
13361        });
13362    }
13363
13364    pub fn delete_to_previous_subword_start(
13365        &mut self,
13366        _: &DeleteToPreviousSubwordStart,
13367        window: &mut Window,
13368        cx: &mut Context<Self>,
13369    ) {
13370        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13371        self.transact(window, cx, |this, window, cx| {
13372            this.select_autoclose_pair(window, cx);
13373            this.change_selections(Default::default(), window, cx, |s| {
13374                s.move_with(|map, selection| {
13375                    if selection.is_empty() {
13376                        let mut cursor = movement::previous_subword_start(map, selection.head());
13377                        cursor =
13378                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13379                        selection.set_head(cursor, SelectionGoal::None);
13380                    }
13381                });
13382            });
13383            this.insert("", window, cx);
13384        });
13385    }
13386
13387    pub fn move_to_next_word_end(
13388        &mut self,
13389        _: &MoveToNextWordEnd,
13390        window: &mut Window,
13391        cx: &mut Context<Self>,
13392    ) {
13393        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13394        self.change_selections(Default::default(), window, cx, |s| {
13395            s.move_cursors_with(|map, head, _| {
13396                (movement::next_word_end(map, head), SelectionGoal::None)
13397            });
13398        })
13399    }
13400
13401    pub fn move_to_next_subword_end(
13402        &mut self,
13403        _: &MoveToNextSubwordEnd,
13404        window: &mut Window,
13405        cx: &mut Context<Self>,
13406    ) {
13407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13408        self.change_selections(Default::default(), window, cx, |s| {
13409            s.move_cursors_with(|map, head, _| {
13410                (movement::next_subword_end(map, head), SelectionGoal::None)
13411            });
13412        })
13413    }
13414
13415    pub fn select_to_next_word_end(
13416        &mut self,
13417        _: &SelectToNextWordEnd,
13418        window: &mut Window,
13419        cx: &mut Context<Self>,
13420    ) {
13421        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13422        self.change_selections(Default::default(), window, cx, |s| {
13423            s.move_heads_with(|map, head, _| {
13424                (movement::next_word_end(map, head), SelectionGoal::None)
13425            });
13426        })
13427    }
13428
13429    pub fn select_to_next_subword_end(
13430        &mut self,
13431        _: &SelectToNextSubwordEnd,
13432        window: &mut Window,
13433        cx: &mut Context<Self>,
13434    ) {
13435        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13436        self.change_selections(Default::default(), window, cx, |s| {
13437            s.move_heads_with(|map, head, _| {
13438                (movement::next_subword_end(map, head), SelectionGoal::None)
13439            });
13440        })
13441    }
13442
13443    pub fn delete_to_next_word_end(
13444        &mut self,
13445        action: &DeleteToNextWordEnd,
13446        window: &mut Window,
13447        cx: &mut Context<Self>,
13448    ) {
13449        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13450        self.transact(window, cx, |this, window, cx| {
13451            this.change_selections(Default::default(), window, cx, |s| {
13452                s.move_with(|map, selection| {
13453                    if selection.is_empty() {
13454                        let mut cursor = if action.ignore_newlines {
13455                            movement::next_word_end(map, selection.head())
13456                        } else {
13457                            movement::next_word_end_or_newline(map, selection.head())
13458                        };
13459                        cursor = movement::adjust_greedy_deletion(
13460                            map,
13461                            selection.head(),
13462                            cursor,
13463                            action.ignore_brackets,
13464                        );
13465                        selection.set_head(cursor, SelectionGoal::None);
13466                    }
13467                });
13468            });
13469            this.insert("", window, cx);
13470        });
13471    }
13472
13473    pub fn delete_to_next_subword_end(
13474        &mut self,
13475        _: &DeleteToNextSubwordEnd,
13476        window: &mut Window,
13477        cx: &mut Context<Self>,
13478    ) {
13479        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13480        self.transact(window, cx, |this, window, cx| {
13481            this.change_selections(Default::default(), window, cx, |s| {
13482                s.move_with(|map, selection| {
13483                    if selection.is_empty() {
13484                        let mut cursor = movement::next_subword_end(map, selection.head());
13485                        cursor =
13486                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13487                        selection.set_head(cursor, SelectionGoal::None);
13488                    }
13489                });
13490            });
13491            this.insert("", window, cx);
13492        });
13493    }
13494
13495    pub fn move_to_beginning_of_line(
13496        &mut self,
13497        action: &MoveToBeginningOfLine,
13498        window: &mut Window,
13499        cx: &mut Context<Self>,
13500    ) {
13501        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13502        self.change_selections(Default::default(), window, cx, |s| {
13503            s.move_cursors_with(|map, head, _| {
13504                (
13505                    movement::indented_line_beginning(
13506                        map,
13507                        head,
13508                        action.stop_at_soft_wraps,
13509                        action.stop_at_indent,
13510                    ),
13511                    SelectionGoal::None,
13512                )
13513            });
13514        })
13515    }
13516
13517    pub fn select_to_beginning_of_line(
13518        &mut self,
13519        action: &SelectToBeginningOfLine,
13520        window: &mut Window,
13521        cx: &mut Context<Self>,
13522    ) {
13523        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13524        self.change_selections(Default::default(), window, cx, |s| {
13525            s.move_heads_with(|map, head, _| {
13526                (
13527                    movement::indented_line_beginning(
13528                        map,
13529                        head,
13530                        action.stop_at_soft_wraps,
13531                        action.stop_at_indent,
13532                    ),
13533                    SelectionGoal::None,
13534                )
13535            });
13536        });
13537    }
13538
13539    pub fn delete_to_beginning_of_line(
13540        &mut self,
13541        action: &DeleteToBeginningOfLine,
13542        window: &mut Window,
13543        cx: &mut Context<Self>,
13544    ) {
13545        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13546        self.transact(window, cx, |this, window, cx| {
13547            this.change_selections(Default::default(), window, cx, |s| {
13548                s.move_with(|_, selection| {
13549                    selection.reversed = true;
13550                });
13551            });
13552
13553            this.select_to_beginning_of_line(
13554                &SelectToBeginningOfLine {
13555                    stop_at_soft_wraps: false,
13556                    stop_at_indent: action.stop_at_indent,
13557                },
13558                window,
13559                cx,
13560            );
13561            this.backspace(&Backspace, window, cx);
13562        });
13563    }
13564
13565    pub fn move_to_end_of_line(
13566        &mut self,
13567        action: &MoveToEndOfLine,
13568        window: &mut Window,
13569        cx: &mut Context<Self>,
13570    ) {
13571        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13572        self.change_selections(Default::default(), window, cx, |s| {
13573            s.move_cursors_with(|map, head, _| {
13574                (
13575                    movement::line_end(map, head, action.stop_at_soft_wraps),
13576                    SelectionGoal::None,
13577                )
13578            });
13579        })
13580    }
13581
13582    pub fn select_to_end_of_line(
13583        &mut self,
13584        action: &SelectToEndOfLine,
13585        window: &mut Window,
13586        cx: &mut Context<Self>,
13587    ) {
13588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13589        self.change_selections(Default::default(), window, cx, |s| {
13590            s.move_heads_with(|map, head, _| {
13591                (
13592                    movement::line_end(map, head, action.stop_at_soft_wraps),
13593                    SelectionGoal::None,
13594                )
13595            });
13596        })
13597    }
13598
13599    pub fn delete_to_end_of_line(
13600        &mut self,
13601        _: &DeleteToEndOfLine,
13602        window: &mut Window,
13603        cx: &mut Context<Self>,
13604    ) {
13605        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13606        self.transact(window, cx, |this, window, cx| {
13607            this.select_to_end_of_line(
13608                &SelectToEndOfLine {
13609                    stop_at_soft_wraps: false,
13610                },
13611                window,
13612                cx,
13613            );
13614            this.delete(&Delete, window, cx);
13615        });
13616    }
13617
13618    pub fn cut_to_end_of_line(
13619        &mut self,
13620        action: &CutToEndOfLine,
13621        window: &mut Window,
13622        cx: &mut Context<Self>,
13623    ) {
13624        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13625        self.transact(window, cx, |this, window, cx| {
13626            this.select_to_end_of_line(
13627                &SelectToEndOfLine {
13628                    stop_at_soft_wraps: false,
13629                },
13630                window,
13631                cx,
13632            );
13633            if !action.stop_at_newlines {
13634                this.change_selections(Default::default(), window, cx, |s| {
13635                    s.move_with(|_, sel| {
13636                        if sel.is_empty() {
13637                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13638                        }
13639                    });
13640                });
13641            }
13642            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13643            let item = this.cut_common(false, window, cx);
13644            cx.write_to_clipboard(item);
13645        });
13646    }
13647
13648    pub fn move_to_start_of_paragraph(
13649        &mut self,
13650        _: &MoveToStartOfParagraph,
13651        window: &mut Window,
13652        cx: &mut Context<Self>,
13653    ) {
13654        if matches!(self.mode, EditorMode::SingleLine) {
13655            cx.propagate();
13656            return;
13657        }
13658        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13659        self.change_selections(Default::default(), window, cx, |s| {
13660            s.move_with(|map, selection| {
13661                selection.collapse_to(
13662                    movement::start_of_paragraph(map, selection.head(), 1),
13663                    SelectionGoal::None,
13664                )
13665            });
13666        })
13667    }
13668
13669    pub fn move_to_end_of_paragraph(
13670        &mut self,
13671        _: &MoveToEndOfParagraph,
13672        window: &mut Window,
13673        cx: &mut Context<Self>,
13674    ) {
13675        if matches!(self.mode, EditorMode::SingleLine) {
13676            cx.propagate();
13677            return;
13678        }
13679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13680        self.change_selections(Default::default(), window, cx, |s| {
13681            s.move_with(|map, selection| {
13682                selection.collapse_to(
13683                    movement::end_of_paragraph(map, selection.head(), 1),
13684                    SelectionGoal::None,
13685                )
13686            });
13687        })
13688    }
13689
13690    pub fn select_to_start_of_paragraph(
13691        &mut self,
13692        _: &SelectToStartOfParagraph,
13693        window: &mut Window,
13694        cx: &mut Context<Self>,
13695    ) {
13696        if matches!(self.mode, EditorMode::SingleLine) {
13697            cx.propagate();
13698            return;
13699        }
13700        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13701        self.change_selections(Default::default(), window, cx, |s| {
13702            s.move_heads_with(|map, head, _| {
13703                (
13704                    movement::start_of_paragraph(map, head, 1),
13705                    SelectionGoal::None,
13706                )
13707            });
13708        })
13709    }
13710
13711    pub fn select_to_end_of_paragraph(
13712        &mut self,
13713        _: &SelectToEndOfParagraph,
13714        window: &mut Window,
13715        cx: &mut Context<Self>,
13716    ) {
13717        if matches!(self.mode, EditorMode::SingleLine) {
13718            cx.propagate();
13719            return;
13720        }
13721        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13722        self.change_selections(Default::default(), window, cx, |s| {
13723            s.move_heads_with(|map, head, _| {
13724                (
13725                    movement::end_of_paragraph(map, head, 1),
13726                    SelectionGoal::None,
13727                )
13728            });
13729        })
13730    }
13731
13732    pub fn move_to_start_of_excerpt(
13733        &mut self,
13734        _: &MoveToStartOfExcerpt,
13735        window: &mut Window,
13736        cx: &mut Context<Self>,
13737    ) {
13738        if matches!(self.mode, EditorMode::SingleLine) {
13739            cx.propagate();
13740            return;
13741        }
13742        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13743        self.change_selections(Default::default(), window, cx, |s| {
13744            s.move_with(|map, selection| {
13745                selection.collapse_to(
13746                    movement::start_of_excerpt(
13747                        map,
13748                        selection.head(),
13749                        workspace::searchable::Direction::Prev,
13750                    ),
13751                    SelectionGoal::None,
13752                )
13753            });
13754        })
13755    }
13756
13757    pub fn move_to_start_of_next_excerpt(
13758        &mut self,
13759        _: &MoveToStartOfNextExcerpt,
13760        window: &mut Window,
13761        cx: &mut Context<Self>,
13762    ) {
13763        if matches!(self.mode, EditorMode::SingleLine) {
13764            cx.propagate();
13765            return;
13766        }
13767
13768        self.change_selections(Default::default(), window, cx, |s| {
13769            s.move_with(|map, selection| {
13770                selection.collapse_to(
13771                    movement::start_of_excerpt(
13772                        map,
13773                        selection.head(),
13774                        workspace::searchable::Direction::Next,
13775                    ),
13776                    SelectionGoal::None,
13777                )
13778            });
13779        })
13780    }
13781
13782    pub fn move_to_end_of_excerpt(
13783        &mut self,
13784        _: &MoveToEndOfExcerpt,
13785        window: &mut Window,
13786        cx: &mut Context<Self>,
13787    ) {
13788        if matches!(self.mode, EditorMode::SingleLine) {
13789            cx.propagate();
13790            return;
13791        }
13792        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13793        self.change_selections(Default::default(), window, cx, |s| {
13794            s.move_with(|map, selection| {
13795                selection.collapse_to(
13796                    movement::end_of_excerpt(
13797                        map,
13798                        selection.head(),
13799                        workspace::searchable::Direction::Next,
13800                    ),
13801                    SelectionGoal::None,
13802                )
13803            });
13804        })
13805    }
13806
13807    pub fn move_to_end_of_previous_excerpt(
13808        &mut self,
13809        _: &MoveToEndOfPreviousExcerpt,
13810        window: &mut Window,
13811        cx: &mut Context<Self>,
13812    ) {
13813        if matches!(self.mode, EditorMode::SingleLine) {
13814            cx.propagate();
13815            return;
13816        }
13817        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13818        self.change_selections(Default::default(), window, cx, |s| {
13819            s.move_with(|map, selection| {
13820                selection.collapse_to(
13821                    movement::end_of_excerpt(
13822                        map,
13823                        selection.head(),
13824                        workspace::searchable::Direction::Prev,
13825                    ),
13826                    SelectionGoal::None,
13827                )
13828            });
13829        })
13830    }
13831
13832    pub fn select_to_start_of_excerpt(
13833        &mut self,
13834        _: &SelectToStartOfExcerpt,
13835        window: &mut Window,
13836        cx: &mut Context<Self>,
13837    ) {
13838        if matches!(self.mode, EditorMode::SingleLine) {
13839            cx.propagate();
13840            return;
13841        }
13842        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13843        self.change_selections(Default::default(), window, cx, |s| {
13844            s.move_heads_with(|map, head, _| {
13845                (
13846                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13847                    SelectionGoal::None,
13848                )
13849            });
13850        })
13851    }
13852
13853    pub fn select_to_start_of_next_excerpt(
13854        &mut self,
13855        _: &SelectToStartOfNextExcerpt,
13856        window: &mut Window,
13857        cx: &mut Context<Self>,
13858    ) {
13859        if matches!(self.mode, EditorMode::SingleLine) {
13860            cx.propagate();
13861            return;
13862        }
13863        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13864        self.change_selections(Default::default(), window, cx, |s| {
13865            s.move_heads_with(|map, head, _| {
13866                (
13867                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13868                    SelectionGoal::None,
13869                )
13870            });
13871        })
13872    }
13873
13874    pub fn select_to_end_of_excerpt(
13875        &mut self,
13876        _: &SelectToEndOfExcerpt,
13877        window: &mut Window,
13878        cx: &mut Context<Self>,
13879    ) {
13880        if matches!(self.mode, EditorMode::SingleLine) {
13881            cx.propagate();
13882            return;
13883        }
13884        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13885        self.change_selections(Default::default(), window, cx, |s| {
13886            s.move_heads_with(|map, head, _| {
13887                (
13888                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13889                    SelectionGoal::None,
13890                )
13891            });
13892        })
13893    }
13894
13895    pub fn select_to_end_of_previous_excerpt(
13896        &mut self,
13897        _: &SelectToEndOfPreviousExcerpt,
13898        window: &mut Window,
13899        cx: &mut Context<Self>,
13900    ) {
13901        if matches!(self.mode, EditorMode::SingleLine) {
13902            cx.propagate();
13903            return;
13904        }
13905        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13906        self.change_selections(Default::default(), window, cx, |s| {
13907            s.move_heads_with(|map, head, _| {
13908                (
13909                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13910                    SelectionGoal::None,
13911                )
13912            });
13913        })
13914    }
13915
13916    pub fn move_to_beginning(
13917        &mut self,
13918        _: &MoveToBeginning,
13919        window: &mut Window,
13920        cx: &mut Context<Self>,
13921    ) {
13922        if matches!(self.mode, EditorMode::SingleLine) {
13923            cx.propagate();
13924            return;
13925        }
13926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13927        self.change_selections(Default::default(), window, cx, |s| {
13928            s.select_ranges(vec![0..0]);
13929        });
13930    }
13931
13932    pub fn select_to_beginning(
13933        &mut self,
13934        _: &SelectToBeginning,
13935        window: &mut Window,
13936        cx: &mut Context<Self>,
13937    ) {
13938        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
13939        selection.set_head(Point::zero(), SelectionGoal::None);
13940        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13941        self.change_selections(Default::default(), window, cx, |s| {
13942            s.select(vec![selection]);
13943        });
13944    }
13945
13946    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13947        if matches!(self.mode, EditorMode::SingleLine) {
13948            cx.propagate();
13949            return;
13950        }
13951        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13952        let cursor = self.buffer.read(cx).read(cx).len();
13953        self.change_selections(Default::default(), window, cx, |s| {
13954            s.select_ranges(vec![cursor..cursor])
13955        });
13956    }
13957
13958    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13959        self.nav_history = nav_history;
13960    }
13961
13962    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13963        self.nav_history.as_ref()
13964    }
13965
13966    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13967        self.push_to_nav_history(
13968            self.selections.newest_anchor().head(),
13969            None,
13970            false,
13971            true,
13972            cx,
13973        );
13974    }
13975
13976    fn push_to_nav_history(
13977        &mut self,
13978        cursor_anchor: Anchor,
13979        new_position: Option<Point>,
13980        is_deactivate: bool,
13981        always: bool,
13982        cx: &mut Context<Self>,
13983    ) {
13984        if let Some(nav_history) = self.nav_history.as_mut() {
13985            let buffer = self.buffer.read(cx).read(cx);
13986            let cursor_position = cursor_anchor.to_point(&buffer);
13987            let scroll_state = self.scroll_manager.anchor();
13988            let scroll_top_row = scroll_state.top_row(&buffer);
13989            drop(buffer);
13990
13991            if let Some(new_position) = new_position {
13992                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13993                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13994                    return;
13995                }
13996            }
13997
13998            nav_history.push(
13999                Some(NavigationData {
14000                    cursor_anchor,
14001                    cursor_position,
14002                    scroll_anchor: scroll_state,
14003                    scroll_top_row,
14004                }),
14005                cx,
14006            );
14007            cx.emit(EditorEvent::PushedToNavHistory {
14008                anchor: cursor_anchor,
14009                is_deactivate,
14010            })
14011        }
14012    }
14013
14014    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14016        let buffer = self.buffer.read(cx).snapshot(cx);
14017        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14018        selection.set_head(buffer.len(), SelectionGoal::None);
14019        self.change_selections(Default::default(), window, cx, |s| {
14020            s.select(vec![selection]);
14021        });
14022    }
14023
14024    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14025        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14026        let end = self.buffer.read(cx).read(cx).len();
14027        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14028            s.select_ranges(vec![0..end]);
14029        });
14030    }
14031
14032    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14033        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14034        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14035        let mut selections = self.selections.all::<Point>(&display_map);
14036        let max_point = display_map.buffer_snapshot().max_point();
14037        for selection in &mut selections {
14038            let rows = selection.spanned_rows(true, &display_map);
14039            selection.start = Point::new(rows.start.0, 0);
14040            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14041            selection.reversed = false;
14042        }
14043        self.change_selections(Default::default(), window, cx, |s| {
14044            s.select(selections);
14045        });
14046    }
14047
14048    pub fn split_selection_into_lines(
14049        &mut self,
14050        action: &SplitSelectionIntoLines,
14051        window: &mut Window,
14052        cx: &mut Context<Self>,
14053    ) {
14054        let selections = self
14055            .selections
14056            .all::<Point>(&self.display_snapshot(cx))
14057            .into_iter()
14058            .map(|selection| selection.start..selection.end)
14059            .collect::<Vec<_>>();
14060        self.unfold_ranges(&selections, true, true, cx);
14061
14062        let mut new_selection_ranges = Vec::new();
14063        {
14064            let buffer = self.buffer.read(cx).read(cx);
14065            for selection in selections {
14066                for row in selection.start.row..selection.end.row {
14067                    let line_start = Point::new(row, 0);
14068                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14069
14070                    if action.keep_selections {
14071                        // Keep the selection range for each line
14072                        let selection_start = if row == selection.start.row {
14073                            selection.start
14074                        } else {
14075                            line_start
14076                        };
14077                        new_selection_ranges.push(selection_start..line_end);
14078                    } else {
14079                        // Collapse to cursor at end of line
14080                        new_selection_ranges.push(line_end..line_end);
14081                    }
14082                }
14083
14084                let is_multiline_selection = selection.start.row != selection.end.row;
14085                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14086                // so this action feels more ergonomic when paired with other selection operations
14087                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14088                if !should_skip_last {
14089                    if action.keep_selections {
14090                        if is_multiline_selection {
14091                            let line_start = Point::new(selection.end.row, 0);
14092                            new_selection_ranges.push(line_start..selection.end);
14093                        } else {
14094                            new_selection_ranges.push(selection.start..selection.end);
14095                        }
14096                    } else {
14097                        new_selection_ranges.push(selection.end..selection.end);
14098                    }
14099                }
14100            }
14101        }
14102        self.change_selections(Default::default(), window, cx, |s| {
14103            s.select_ranges(new_selection_ranges);
14104        });
14105    }
14106
14107    pub fn add_selection_above(
14108        &mut self,
14109        action: &AddSelectionAbove,
14110        window: &mut Window,
14111        cx: &mut Context<Self>,
14112    ) {
14113        self.add_selection(true, action.skip_soft_wrap, window, cx);
14114    }
14115
14116    pub fn add_selection_below(
14117        &mut self,
14118        action: &AddSelectionBelow,
14119        window: &mut Window,
14120        cx: &mut Context<Self>,
14121    ) {
14122        self.add_selection(false, action.skip_soft_wrap, window, cx);
14123    }
14124
14125    fn add_selection(
14126        &mut self,
14127        above: bool,
14128        skip_soft_wrap: bool,
14129        window: &mut Window,
14130        cx: &mut Context<Self>,
14131    ) {
14132        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14133
14134        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14135        let all_selections = self.selections.all::<Point>(&display_map);
14136        let text_layout_details = self.text_layout_details(window);
14137
14138        let (mut columnar_selections, new_selections_to_columnarize) = {
14139            if let Some(state) = self.add_selections_state.as_ref() {
14140                let columnar_selection_ids: HashSet<_> = state
14141                    .groups
14142                    .iter()
14143                    .flat_map(|group| group.stack.iter())
14144                    .copied()
14145                    .collect();
14146
14147                all_selections
14148                    .into_iter()
14149                    .partition(|s| columnar_selection_ids.contains(&s.id))
14150            } else {
14151                (Vec::new(), all_selections)
14152            }
14153        };
14154
14155        let mut state = self
14156            .add_selections_state
14157            .take()
14158            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14159
14160        for selection in new_selections_to_columnarize {
14161            let range = selection.display_range(&display_map).sorted();
14162            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14163            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14164            let positions = start_x.min(end_x)..start_x.max(end_x);
14165            let mut stack = Vec::new();
14166            for row in range.start.row().0..=range.end.row().0 {
14167                if let Some(selection) = self.selections.build_columnar_selection(
14168                    &display_map,
14169                    DisplayRow(row),
14170                    &positions,
14171                    selection.reversed,
14172                    &text_layout_details,
14173                ) {
14174                    stack.push(selection.id);
14175                    columnar_selections.push(selection);
14176                }
14177            }
14178            if !stack.is_empty() {
14179                if above {
14180                    stack.reverse();
14181                }
14182                state.groups.push(AddSelectionsGroup { above, stack });
14183            }
14184        }
14185
14186        let mut final_selections = Vec::new();
14187        let end_row = if above {
14188            DisplayRow(0)
14189        } else {
14190            display_map.max_point().row()
14191        };
14192
14193        let mut last_added_item_per_group = HashMap::default();
14194        for group in state.groups.iter_mut() {
14195            if let Some(last_id) = group.stack.last() {
14196                last_added_item_per_group.insert(*last_id, group);
14197            }
14198        }
14199
14200        for selection in columnar_selections {
14201            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14202                if above == group.above {
14203                    let range = selection.display_range(&display_map).sorted();
14204                    debug_assert_eq!(range.start.row(), range.end.row());
14205                    let mut row = range.start.row();
14206                    let positions =
14207                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14208                            Pixels::from(start)..Pixels::from(end)
14209                        } else {
14210                            let start_x =
14211                                display_map.x_for_display_point(range.start, &text_layout_details);
14212                            let end_x =
14213                                display_map.x_for_display_point(range.end, &text_layout_details);
14214                            start_x.min(end_x)..start_x.max(end_x)
14215                        };
14216
14217                    let mut maybe_new_selection = None;
14218                    let direction = if above { -1 } else { 1 };
14219
14220                    while row != end_row {
14221                        if skip_soft_wrap {
14222                            row = display_map
14223                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14224                                .row();
14225                        } else if above {
14226                            row.0 -= 1;
14227                        } else {
14228                            row.0 += 1;
14229                        }
14230
14231                        if let Some(new_selection) = self.selections.build_columnar_selection(
14232                            &display_map,
14233                            row,
14234                            &positions,
14235                            selection.reversed,
14236                            &text_layout_details,
14237                        ) {
14238                            maybe_new_selection = Some(new_selection);
14239                            break;
14240                        }
14241                    }
14242
14243                    if let Some(new_selection) = maybe_new_selection {
14244                        group.stack.push(new_selection.id);
14245                        if above {
14246                            final_selections.push(new_selection);
14247                            final_selections.push(selection);
14248                        } else {
14249                            final_selections.push(selection);
14250                            final_selections.push(new_selection);
14251                        }
14252                    } else {
14253                        final_selections.push(selection);
14254                    }
14255                } else {
14256                    group.stack.pop();
14257                }
14258            } else {
14259                final_selections.push(selection);
14260            }
14261        }
14262
14263        self.change_selections(Default::default(), window, cx, |s| {
14264            s.select(final_selections);
14265        });
14266
14267        let final_selection_ids: HashSet<_> = self
14268            .selections
14269            .all::<Point>(&display_map)
14270            .iter()
14271            .map(|s| s.id)
14272            .collect();
14273        state.groups.retain_mut(|group| {
14274            // selections might get merged above so we remove invalid items from stacks
14275            group.stack.retain(|id| final_selection_ids.contains(id));
14276
14277            // single selection in stack can be treated as initial state
14278            group.stack.len() > 1
14279        });
14280
14281        if !state.groups.is_empty() {
14282            self.add_selections_state = Some(state);
14283        }
14284    }
14285
14286    fn select_match_ranges(
14287        &mut self,
14288        range: Range<usize>,
14289        reversed: bool,
14290        replace_newest: bool,
14291        auto_scroll: Option<Autoscroll>,
14292        window: &mut Window,
14293        cx: &mut Context<Editor>,
14294    ) {
14295        self.unfold_ranges(
14296            std::slice::from_ref(&range),
14297            false,
14298            auto_scroll.is_some(),
14299            cx,
14300        );
14301        let effects = if let Some(scroll) = auto_scroll {
14302            SelectionEffects::scroll(scroll)
14303        } else {
14304            SelectionEffects::no_scroll()
14305        };
14306        self.change_selections(effects, window, cx, |s| {
14307            if replace_newest {
14308                s.delete(s.newest_anchor().id);
14309            }
14310            if reversed {
14311                s.insert_range(range.end..range.start);
14312            } else {
14313                s.insert_range(range);
14314            }
14315        });
14316    }
14317
14318    pub fn select_next_match_internal(
14319        &mut self,
14320        display_map: &DisplaySnapshot,
14321        replace_newest: bool,
14322        autoscroll: Option<Autoscroll>,
14323        window: &mut Window,
14324        cx: &mut Context<Self>,
14325    ) -> Result<()> {
14326        let buffer = display_map.buffer_snapshot();
14327        let mut selections = self.selections.all::<usize>(&display_map);
14328        if let Some(mut select_next_state) = self.select_next_state.take() {
14329            let query = &select_next_state.query;
14330            if !select_next_state.done {
14331                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14332                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14333                let mut next_selected_range = None;
14334
14335                // Collect and sort selection ranges for efficient overlap checking
14336                let mut selection_ranges: Vec<_> = selections.iter().map(|s| s.range()).collect();
14337                selection_ranges.sort_by_key(|r| r.start);
14338
14339                let bytes_after_last_selection =
14340                    buffer.bytes_in_range(last_selection.end..buffer.len());
14341                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14342                let query_matches = query
14343                    .stream_find_iter(bytes_after_last_selection)
14344                    .map(|result| (last_selection.end, result))
14345                    .chain(
14346                        query
14347                            .stream_find_iter(bytes_before_first_selection)
14348                            .map(|result| (0, result)),
14349                    );
14350
14351                for (start_offset, query_match) in query_matches {
14352                    let query_match = query_match.unwrap(); // can only fail due to I/O
14353                    let offset_range =
14354                        start_offset + query_match.start()..start_offset + query_match.end();
14355
14356                    if !select_next_state.wordwise
14357                        || (!buffer.is_inside_word(offset_range.start, None)
14358                            && !buffer.is_inside_word(offset_range.end, None))
14359                    {
14360                        // Use binary search to check for overlap (O(log n))
14361                        let overlaps = selection_ranges
14362                            .binary_search_by(|range| {
14363                                if range.end <= offset_range.start {
14364                                    std::cmp::Ordering::Less
14365                                } else if range.start >= offset_range.end {
14366                                    std::cmp::Ordering::Greater
14367                                } else {
14368                                    std::cmp::Ordering::Equal
14369                                }
14370                            })
14371                            .is_ok();
14372
14373                        if !overlaps {
14374                            next_selected_range = Some(offset_range);
14375                            break;
14376                        }
14377                    }
14378                }
14379
14380                if let Some(next_selected_range) = next_selected_range {
14381                    self.select_match_ranges(
14382                        next_selected_range,
14383                        last_selection.reversed,
14384                        replace_newest,
14385                        autoscroll,
14386                        window,
14387                        cx,
14388                    );
14389                } else {
14390                    select_next_state.done = true;
14391                }
14392            }
14393
14394            self.select_next_state = Some(select_next_state);
14395        } else {
14396            let mut only_carets = true;
14397            let mut same_text_selected = true;
14398            let mut selected_text = None;
14399
14400            let mut selections_iter = selections.iter().peekable();
14401            while let Some(selection) = selections_iter.next() {
14402                if selection.start != selection.end {
14403                    only_carets = false;
14404                }
14405
14406                if same_text_selected {
14407                    if selected_text.is_none() {
14408                        selected_text =
14409                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14410                    }
14411
14412                    if let Some(next_selection) = selections_iter.peek() {
14413                        if next_selection.range().len() == selection.range().len() {
14414                            let next_selected_text = buffer
14415                                .text_for_range(next_selection.range())
14416                                .collect::<String>();
14417                            if Some(next_selected_text) != selected_text {
14418                                same_text_selected = false;
14419                                selected_text = None;
14420                            }
14421                        } else {
14422                            same_text_selected = false;
14423                            selected_text = None;
14424                        }
14425                    }
14426                }
14427            }
14428
14429            if only_carets {
14430                for selection in &mut selections {
14431                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14432                    selection.start = word_range.start;
14433                    selection.end = word_range.end;
14434                    selection.goal = SelectionGoal::None;
14435                    selection.reversed = false;
14436                    self.select_match_ranges(
14437                        selection.start..selection.end,
14438                        selection.reversed,
14439                        replace_newest,
14440                        autoscroll,
14441                        window,
14442                        cx,
14443                    );
14444                }
14445
14446                if selections.len() == 1 {
14447                    let selection = selections
14448                        .last()
14449                        .expect("ensured that there's only one selection");
14450                    let query = buffer
14451                        .text_for_range(selection.start..selection.end)
14452                        .collect::<String>();
14453                    let is_empty = query.is_empty();
14454                    let select_state = SelectNextState {
14455                        query: AhoCorasick::new(&[query])?,
14456                        wordwise: true,
14457                        done: is_empty,
14458                    };
14459                    self.select_next_state = Some(select_state);
14460                } else {
14461                    self.select_next_state = None;
14462                }
14463            } else if let Some(selected_text) = selected_text {
14464                self.select_next_state = Some(SelectNextState {
14465                    query: AhoCorasick::new(&[selected_text])?,
14466                    wordwise: false,
14467                    done: false,
14468                });
14469                self.select_next_match_internal(
14470                    display_map,
14471                    replace_newest,
14472                    autoscroll,
14473                    window,
14474                    cx,
14475                )?;
14476            }
14477        }
14478        Ok(())
14479    }
14480
14481    pub fn select_all_matches(
14482        &mut self,
14483        _action: &SelectAllMatches,
14484        window: &mut Window,
14485        cx: &mut Context<Self>,
14486    ) -> Result<()> {
14487        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14488
14489        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14490
14491        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14492        let Some(select_next_state) = self.select_next_state.as_mut() else {
14493            return Ok(());
14494        };
14495        if select_next_state.done {
14496            return Ok(());
14497        }
14498
14499        let mut new_selections = Vec::new();
14500
14501        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14502        let buffer = display_map.buffer_snapshot();
14503        let query_matches = select_next_state
14504            .query
14505            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14506
14507        for query_match in query_matches.into_iter() {
14508            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14509            let offset_range = if reversed {
14510                query_match.end()..query_match.start()
14511            } else {
14512                query_match.start()..query_match.end()
14513            };
14514
14515            if !select_next_state.wordwise
14516                || (!buffer.is_inside_word(offset_range.start, None)
14517                    && !buffer.is_inside_word(offset_range.end, None))
14518            {
14519                new_selections.push(offset_range.start..offset_range.end);
14520            }
14521        }
14522
14523        select_next_state.done = true;
14524
14525        if new_selections.is_empty() {
14526            log::error!("bug: new_selections is empty in select_all_matches");
14527            return Ok(());
14528        }
14529
14530        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14531        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14532            selections.select_ranges(new_selections)
14533        });
14534
14535        Ok(())
14536    }
14537
14538    pub fn select_next(
14539        &mut self,
14540        action: &SelectNext,
14541        window: &mut Window,
14542        cx: &mut Context<Self>,
14543    ) -> Result<()> {
14544        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14545        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14546        self.select_next_match_internal(
14547            &display_map,
14548            action.replace_newest,
14549            Some(Autoscroll::newest()),
14550            window,
14551            cx,
14552        )?;
14553        Ok(())
14554    }
14555
14556    pub fn select_previous(
14557        &mut self,
14558        action: &SelectPrevious,
14559        window: &mut Window,
14560        cx: &mut Context<Self>,
14561    ) -> Result<()> {
14562        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14563        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14564        let buffer = display_map.buffer_snapshot();
14565        let mut selections = self.selections.all::<usize>(&display_map);
14566        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14567            let query = &select_prev_state.query;
14568            if !select_prev_state.done {
14569                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14570                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14571                let mut next_selected_range = None;
14572                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14573                let bytes_before_last_selection =
14574                    buffer.reversed_bytes_in_range(0..last_selection.start);
14575                let bytes_after_first_selection =
14576                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14577                let query_matches = query
14578                    .stream_find_iter(bytes_before_last_selection)
14579                    .map(|result| (last_selection.start, result))
14580                    .chain(
14581                        query
14582                            .stream_find_iter(bytes_after_first_selection)
14583                            .map(|result| (buffer.len(), result)),
14584                    );
14585                for (end_offset, query_match) in query_matches {
14586                    let query_match = query_match.unwrap(); // can only fail due to I/O
14587                    let offset_range =
14588                        end_offset - query_match.end()..end_offset - query_match.start();
14589
14590                    if !select_prev_state.wordwise
14591                        || (!buffer.is_inside_word(offset_range.start, None)
14592                            && !buffer.is_inside_word(offset_range.end, None))
14593                    {
14594                        next_selected_range = Some(offset_range);
14595                        break;
14596                    }
14597                }
14598
14599                if let Some(next_selected_range) = next_selected_range {
14600                    self.select_match_ranges(
14601                        next_selected_range,
14602                        last_selection.reversed,
14603                        action.replace_newest,
14604                        Some(Autoscroll::newest()),
14605                        window,
14606                        cx,
14607                    );
14608                } else {
14609                    select_prev_state.done = true;
14610                }
14611            }
14612
14613            self.select_prev_state = Some(select_prev_state);
14614        } else {
14615            let mut only_carets = true;
14616            let mut same_text_selected = true;
14617            let mut selected_text = None;
14618
14619            let mut selections_iter = selections.iter().peekable();
14620            while let Some(selection) = selections_iter.next() {
14621                if selection.start != selection.end {
14622                    only_carets = false;
14623                }
14624
14625                if same_text_selected {
14626                    if selected_text.is_none() {
14627                        selected_text =
14628                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14629                    }
14630
14631                    if let Some(next_selection) = selections_iter.peek() {
14632                        if next_selection.range().len() == selection.range().len() {
14633                            let next_selected_text = buffer
14634                                .text_for_range(next_selection.range())
14635                                .collect::<String>();
14636                            if Some(next_selected_text) != selected_text {
14637                                same_text_selected = false;
14638                                selected_text = None;
14639                            }
14640                        } else {
14641                            same_text_selected = false;
14642                            selected_text = None;
14643                        }
14644                    }
14645                }
14646            }
14647
14648            if only_carets {
14649                for selection in &mut selections {
14650                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14651                    selection.start = word_range.start;
14652                    selection.end = word_range.end;
14653                    selection.goal = SelectionGoal::None;
14654                    selection.reversed = false;
14655                    self.select_match_ranges(
14656                        selection.start..selection.end,
14657                        selection.reversed,
14658                        action.replace_newest,
14659                        Some(Autoscroll::newest()),
14660                        window,
14661                        cx,
14662                    );
14663                }
14664                if selections.len() == 1 {
14665                    let selection = selections
14666                        .last()
14667                        .expect("ensured that there's only one selection");
14668                    let query = buffer
14669                        .text_for_range(selection.start..selection.end)
14670                        .collect::<String>();
14671                    let is_empty = query.is_empty();
14672                    let select_state = SelectNextState {
14673                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14674                        wordwise: true,
14675                        done: is_empty,
14676                    };
14677                    self.select_prev_state = Some(select_state);
14678                } else {
14679                    self.select_prev_state = None;
14680                }
14681            } else if let Some(selected_text) = selected_text {
14682                self.select_prev_state = Some(SelectNextState {
14683                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14684                    wordwise: false,
14685                    done: false,
14686                });
14687                self.select_previous(action, window, cx)?;
14688            }
14689        }
14690        Ok(())
14691    }
14692
14693    pub fn find_next_match(
14694        &mut self,
14695        _: &FindNextMatch,
14696        window: &mut Window,
14697        cx: &mut Context<Self>,
14698    ) -> Result<()> {
14699        let selections = self.selections.disjoint_anchors_arc();
14700        match selections.first() {
14701            Some(first) if selections.len() >= 2 => {
14702                self.change_selections(Default::default(), window, cx, |s| {
14703                    s.select_ranges([first.range()]);
14704                });
14705            }
14706            _ => self.select_next(
14707                &SelectNext {
14708                    replace_newest: true,
14709                },
14710                window,
14711                cx,
14712            )?,
14713        }
14714        Ok(())
14715    }
14716
14717    pub fn find_previous_match(
14718        &mut self,
14719        _: &FindPreviousMatch,
14720        window: &mut Window,
14721        cx: &mut Context<Self>,
14722    ) -> Result<()> {
14723        let selections = self.selections.disjoint_anchors_arc();
14724        match selections.last() {
14725            Some(last) if selections.len() >= 2 => {
14726                self.change_selections(Default::default(), window, cx, |s| {
14727                    s.select_ranges([last.range()]);
14728                });
14729            }
14730            _ => self.select_previous(
14731                &SelectPrevious {
14732                    replace_newest: true,
14733                },
14734                window,
14735                cx,
14736            )?,
14737        }
14738        Ok(())
14739    }
14740
14741    pub fn toggle_comments(
14742        &mut self,
14743        action: &ToggleComments,
14744        window: &mut Window,
14745        cx: &mut Context<Self>,
14746    ) {
14747        if self.read_only(cx) {
14748            return;
14749        }
14750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14751        let text_layout_details = &self.text_layout_details(window);
14752        self.transact(window, cx, |this, window, cx| {
14753            let mut selections = this
14754                .selections
14755                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14756            let mut edits = Vec::new();
14757            let mut selection_edit_ranges = Vec::new();
14758            let mut last_toggled_row = None;
14759            let snapshot = this.buffer.read(cx).read(cx);
14760            let empty_str: Arc<str> = Arc::default();
14761            let mut suffixes_inserted = Vec::new();
14762            let ignore_indent = action.ignore_indent;
14763
14764            fn comment_prefix_range(
14765                snapshot: &MultiBufferSnapshot,
14766                row: MultiBufferRow,
14767                comment_prefix: &str,
14768                comment_prefix_whitespace: &str,
14769                ignore_indent: bool,
14770            ) -> Range<Point> {
14771                let indent_size = if ignore_indent {
14772                    0
14773                } else {
14774                    snapshot.indent_size_for_line(row).len
14775                };
14776
14777                let start = Point::new(row.0, indent_size);
14778
14779                let mut line_bytes = snapshot
14780                    .bytes_in_range(start..snapshot.max_point())
14781                    .flatten()
14782                    .copied();
14783
14784                // If this line currently begins with the line comment prefix, then record
14785                // the range containing the prefix.
14786                if line_bytes
14787                    .by_ref()
14788                    .take(comment_prefix.len())
14789                    .eq(comment_prefix.bytes())
14790                {
14791                    // Include any whitespace that matches the comment prefix.
14792                    let matching_whitespace_len = line_bytes
14793                        .zip(comment_prefix_whitespace.bytes())
14794                        .take_while(|(a, b)| a == b)
14795                        .count() as u32;
14796                    let end = Point::new(
14797                        start.row,
14798                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14799                    );
14800                    start..end
14801                } else {
14802                    start..start
14803                }
14804            }
14805
14806            fn comment_suffix_range(
14807                snapshot: &MultiBufferSnapshot,
14808                row: MultiBufferRow,
14809                comment_suffix: &str,
14810                comment_suffix_has_leading_space: bool,
14811            ) -> Range<Point> {
14812                let end = Point::new(row.0, snapshot.line_len(row));
14813                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14814
14815                let mut line_end_bytes = snapshot
14816                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14817                    .flatten()
14818                    .copied();
14819
14820                let leading_space_len = if suffix_start_column > 0
14821                    && line_end_bytes.next() == Some(b' ')
14822                    && comment_suffix_has_leading_space
14823                {
14824                    1
14825                } else {
14826                    0
14827                };
14828
14829                // If this line currently begins with the line comment prefix, then record
14830                // the range containing the prefix.
14831                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14832                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14833                    start..end
14834                } else {
14835                    end..end
14836                }
14837            }
14838
14839            // TODO: Handle selections that cross excerpts
14840            for selection in &mut selections {
14841                let start_column = snapshot
14842                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14843                    .len;
14844                let language = if let Some(language) =
14845                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14846                {
14847                    language
14848                } else {
14849                    continue;
14850                };
14851
14852                selection_edit_ranges.clear();
14853
14854                // If multiple selections contain a given row, avoid processing that
14855                // row more than once.
14856                let mut start_row = MultiBufferRow(selection.start.row);
14857                if last_toggled_row == Some(start_row) {
14858                    start_row = start_row.next_row();
14859                }
14860                let end_row =
14861                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14862                        MultiBufferRow(selection.end.row - 1)
14863                    } else {
14864                        MultiBufferRow(selection.end.row)
14865                    };
14866                last_toggled_row = Some(end_row);
14867
14868                if start_row > end_row {
14869                    continue;
14870                }
14871
14872                // If the language has line comments, toggle those.
14873                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14874
14875                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14876                if ignore_indent {
14877                    full_comment_prefixes = full_comment_prefixes
14878                        .into_iter()
14879                        .map(|s| Arc::from(s.trim_end()))
14880                        .collect();
14881                }
14882
14883                if !full_comment_prefixes.is_empty() {
14884                    let first_prefix = full_comment_prefixes
14885                        .first()
14886                        .expect("prefixes is non-empty");
14887                    let prefix_trimmed_lengths = full_comment_prefixes
14888                        .iter()
14889                        .map(|p| p.trim_end_matches(' ').len())
14890                        .collect::<SmallVec<[usize; 4]>>();
14891
14892                    let mut all_selection_lines_are_comments = true;
14893
14894                    for row in start_row.0..=end_row.0 {
14895                        let row = MultiBufferRow(row);
14896                        if start_row < end_row && snapshot.is_line_blank(row) {
14897                            continue;
14898                        }
14899
14900                        let prefix_range = full_comment_prefixes
14901                            .iter()
14902                            .zip(prefix_trimmed_lengths.iter().copied())
14903                            .map(|(prefix, trimmed_prefix_len)| {
14904                                comment_prefix_range(
14905                                    snapshot.deref(),
14906                                    row,
14907                                    &prefix[..trimmed_prefix_len],
14908                                    &prefix[trimmed_prefix_len..],
14909                                    ignore_indent,
14910                                )
14911                            })
14912                            .max_by_key(|range| range.end.column - range.start.column)
14913                            .expect("prefixes is non-empty");
14914
14915                        if prefix_range.is_empty() {
14916                            all_selection_lines_are_comments = false;
14917                        }
14918
14919                        selection_edit_ranges.push(prefix_range);
14920                    }
14921
14922                    if all_selection_lines_are_comments {
14923                        edits.extend(
14924                            selection_edit_ranges
14925                                .iter()
14926                                .cloned()
14927                                .map(|range| (range, empty_str.clone())),
14928                        );
14929                    } else {
14930                        let min_column = selection_edit_ranges
14931                            .iter()
14932                            .map(|range| range.start.column)
14933                            .min()
14934                            .unwrap_or(0);
14935                        edits.extend(selection_edit_ranges.iter().map(|range| {
14936                            let position = Point::new(range.start.row, min_column);
14937                            (position..position, first_prefix.clone())
14938                        }));
14939                    }
14940                } else if let Some(BlockCommentConfig {
14941                    start: full_comment_prefix,
14942                    end: comment_suffix,
14943                    ..
14944                }) = language.block_comment()
14945                {
14946                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14947                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14948                    let prefix_range = comment_prefix_range(
14949                        snapshot.deref(),
14950                        start_row,
14951                        comment_prefix,
14952                        comment_prefix_whitespace,
14953                        ignore_indent,
14954                    );
14955                    let suffix_range = comment_suffix_range(
14956                        snapshot.deref(),
14957                        end_row,
14958                        comment_suffix.trim_start_matches(' '),
14959                        comment_suffix.starts_with(' '),
14960                    );
14961
14962                    if prefix_range.is_empty() || suffix_range.is_empty() {
14963                        edits.push((
14964                            prefix_range.start..prefix_range.start,
14965                            full_comment_prefix.clone(),
14966                        ));
14967                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14968                        suffixes_inserted.push((end_row, comment_suffix.len()));
14969                    } else {
14970                        edits.push((prefix_range, empty_str.clone()));
14971                        edits.push((suffix_range, empty_str.clone()));
14972                    }
14973                } else {
14974                    continue;
14975                }
14976            }
14977
14978            drop(snapshot);
14979            this.buffer.update(cx, |buffer, cx| {
14980                buffer.edit(edits, None, cx);
14981            });
14982
14983            // Adjust selections so that they end before any comment suffixes that
14984            // were inserted.
14985            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14986            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
14987            let snapshot = this.buffer.read(cx).read(cx);
14988            for selection in &mut selections {
14989                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14990                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14991                        Ordering::Less => {
14992                            suffixes_inserted.next();
14993                            continue;
14994                        }
14995                        Ordering::Greater => break,
14996                        Ordering::Equal => {
14997                            if selection.end.column == snapshot.line_len(row) {
14998                                if selection.is_empty() {
14999                                    selection.start.column -= suffix_len as u32;
15000                                }
15001                                selection.end.column -= suffix_len as u32;
15002                            }
15003                            break;
15004                        }
15005                    }
15006                }
15007            }
15008
15009            drop(snapshot);
15010            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15011
15012            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15013            let selections_on_single_row = selections.windows(2).all(|selections| {
15014                selections[0].start.row == selections[1].start.row
15015                    && selections[0].end.row == selections[1].end.row
15016                    && selections[0].start.row == selections[0].end.row
15017            });
15018            let selections_selecting = selections
15019                .iter()
15020                .any(|selection| selection.start != selection.end);
15021            let advance_downwards = action.advance_downwards
15022                && selections_on_single_row
15023                && !selections_selecting
15024                && !matches!(this.mode, EditorMode::SingleLine);
15025
15026            if advance_downwards {
15027                let snapshot = this.buffer.read(cx).snapshot(cx);
15028
15029                this.change_selections(Default::default(), window, cx, |s| {
15030                    s.move_cursors_with(|display_snapshot, display_point, _| {
15031                        let mut point = display_point.to_point(display_snapshot);
15032                        point.row += 1;
15033                        point = snapshot.clip_point(point, Bias::Left);
15034                        let display_point = point.to_display_point(display_snapshot);
15035                        let goal = SelectionGoal::HorizontalPosition(
15036                            display_snapshot
15037                                .x_for_display_point(display_point, text_layout_details)
15038                                .into(),
15039                        );
15040                        (display_point, goal)
15041                    })
15042                });
15043            }
15044        });
15045    }
15046
15047    pub fn select_enclosing_symbol(
15048        &mut self,
15049        _: &SelectEnclosingSymbol,
15050        window: &mut Window,
15051        cx: &mut Context<Self>,
15052    ) {
15053        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15054
15055        let buffer = self.buffer.read(cx).snapshot(cx);
15056        let old_selections = self
15057            .selections
15058            .all::<usize>(&self.display_snapshot(cx))
15059            .into_boxed_slice();
15060
15061        fn update_selection(
15062            selection: &Selection<usize>,
15063            buffer_snap: &MultiBufferSnapshot,
15064        ) -> Option<Selection<usize>> {
15065            let cursor = selection.head();
15066            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15067            for symbol in symbols.iter().rev() {
15068                let start = symbol.range.start.to_offset(buffer_snap);
15069                let end = symbol.range.end.to_offset(buffer_snap);
15070                let new_range = start..end;
15071                if start < selection.start || end > selection.end {
15072                    return Some(Selection {
15073                        id: selection.id,
15074                        start: new_range.start,
15075                        end: new_range.end,
15076                        goal: SelectionGoal::None,
15077                        reversed: selection.reversed,
15078                    });
15079                }
15080            }
15081            None
15082        }
15083
15084        let mut selected_larger_symbol = false;
15085        let new_selections = old_selections
15086            .iter()
15087            .map(|selection| match update_selection(selection, &buffer) {
15088                Some(new_selection) => {
15089                    if new_selection.range() != selection.range() {
15090                        selected_larger_symbol = true;
15091                    }
15092                    new_selection
15093                }
15094                None => selection.clone(),
15095            })
15096            .collect::<Vec<_>>();
15097
15098        if selected_larger_symbol {
15099            self.change_selections(Default::default(), window, cx, |s| {
15100                s.select(new_selections);
15101            });
15102        }
15103    }
15104
15105    pub fn select_larger_syntax_node(
15106        &mut self,
15107        _: &SelectLargerSyntaxNode,
15108        window: &mut Window,
15109        cx: &mut Context<Self>,
15110    ) {
15111        let Some(visible_row_count) = self.visible_row_count() else {
15112            return;
15113        };
15114        let old_selections: Box<[_]> = self
15115            .selections
15116            .all::<usize>(&self.display_snapshot(cx))
15117            .into();
15118        if old_selections.is_empty() {
15119            return;
15120        }
15121
15122        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15123
15124        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15125        let buffer = self.buffer.read(cx).snapshot(cx);
15126
15127        let mut selected_larger_node = false;
15128        let mut new_selections = old_selections
15129            .iter()
15130            .map(|selection| {
15131                let old_range = selection.start..selection.end;
15132
15133                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15134                    // manually select word at selection
15135                    if ["string_content", "inline"].contains(&node.kind()) {
15136                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15137                        // ignore if word is already selected
15138                        if !word_range.is_empty() && old_range != word_range {
15139                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15140                            // only select word if start and end point belongs to same word
15141                            if word_range == last_word_range {
15142                                selected_larger_node = true;
15143                                return Selection {
15144                                    id: selection.id,
15145                                    start: word_range.start,
15146                                    end: word_range.end,
15147                                    goal: SelectionGoal::None,
15148                                    reversed: selection.reversed,
15149                                };
15150                            }
15151                        }
15152                    }
15153                }
15154
15155                let mut new_range = old_range.clone();
15156                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15157                    new_range = range;
15158                    if !node.is_named() {
15159                        continue;
15160                    }
15161                    if !display_map.intersects_fold(new_range.start)
15162                        && !display_map.intersects_fold(new_range.end)
15163                    {
15164                        break;
15165                    }
15166                }
15167
15168                selected_larger_node |= new_range != old_range;
15169                Selection {
15170                    id: selection.id,
15171                    start: new_range.start,
15172                    end: new_range.end,
15173                    goal: SelectionGoal::None,
15174                    reversed: selection.reversed,
15175                }
15176            })
15177            .collect::<Vec<_>>();
15178
15179        if !selected_larger_node {
15180            return; // don't put this call in the history
15181        }
15182
15183        // scroll based on transformation done to the last selection created by the user
15184        let (last_old, last_new) = old_selections
15185            .last()
15186            .zip(new_selections.last().cloned())
15187            .expect("old_selections isn't empty");
15188
15189        // revert selection
15190        let is_selection_reversed = {
15191            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15192            new_selections.last_mut().expect("checked above").reversed =
15193                should_newest_selection_be_reversed;
15194            should_newest_selection_be_reversed
15195        };
15196
15197        if selected_larger_node {
15198            self.select_syntax_node_history.disable_clearing = true;
15199            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15200                s.select(new_selections.clone());
15201            });
15202            self.select_syntax_node_history.disable_clearing = false;
15203        }
15204
15205        let start_row = last_new.start.to_display_point(&display_map).row().0;
15206        let end_row = last_new.end.to_display_point(&display_map).row().0;
15207        let selection_height = end_row - start_row + 1;
15208        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15209
15210        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15211        let scroll_behavior = if fits_on_the_screen {
15212            self.request_autoscroll(Autoscroll::fit(), cx);
15213            SelectSyntaxNodeScrollBehavior::FitSelection
15214        } else if is_selection_reversed {
15215            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15216            SelectSyntaxNodeScrollBehavior::CursorTop
15217        } else {
15218            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15219            SelectSyntaxNodeScrollBehavior::CursorBottom
15220        };
15221
15222        self.select_syntax_node_history.push((
15223            old_selections,
15224            scroll_behavior,
15225            is_selection_reversed,
15226        ));
15227    }
15228
15229    pub fn select_smaller_syntax_node(
15230        &mut self,
15231        _: &SelectSmallerSyntaxNode,
15232        window: &mut Window,
15233        cx: &mut Context<Self>,
15234    ) {
15235        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15236
15237        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15238            self.select_syntax_node_history.pop()
15239        {
15240            if let Some(selection) = selections.last_mut() {
15241                selection.reversed = is_selection_reversed;
15242            }
15243
15244            self.select_syntax_node_history.disable_clearing = true;
15245            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15246                s.select(selections.to_vec());
15247            });
15248            self.select_syntax_node_history.disable_clearing = false;
15249
15250            match scroll_behavior {
15251                SelectSyntaxNodeScrollBehavior::CursorTop => {
15252                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15253                }
15254                SelectSyntaxNodeScrollBehavior::FitSelection => {
15255                    self.request_autoscroll(Autoscroll::fit(), cx);
15256                }
15257                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15258                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15259                }
15260            }
15261        }
15262    }
15263
15264    pub fn unwrap_syntax_node(
15265        &mut self,
15266        _: &UnwrapSyntaxNode,
15267        window: &mut Window,
15268        cx: &mut Context<Self>,
15269    ) {
15270        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15271
15272        let buffer = self.buffer.read(cx).snapshot(cx);
15273        let selections = self
15274            .selections
15275            .all::<usize>(&self.display_snapshot(cx))
15276            .into_iter()
15277            // subtracting the offset requires sorting
15278            .sorted_by_key(|i| i.start);
15279
15280        let full_edits = selections
15281            .into_iter()
15282            .filter_map(|selection| {
15283                let child = if selection.is_empty()
15284                    && let Some((_, ancestor_range)) =
15285                        buffer.syntax_ancestor(selection.start..selection.end)
15286                {
15287                    ancestor_range
15288                } else {
15289                    selection.range()
15290                };
15291
15292                let mut parent = child.clone();
15293                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15294                    parent = ancestor_range;
15295                    if parent.start < child.start || parent.end > child.end {
15296                        break;
15297                    }
15298                }
15299
15300                if parent == child {
15301                    return None;
15302                }
15303                let text = buffer.text_for_range(child).collect::<String>();
15304                Some((selection.id, parent, text))
15305            })
15306            .collect::<Vec<_>>();
15307        if full_edits.is_empty() {
15308            return;
15309        }
15310
15311        self.transact(window, cx, |this, window, cx| {
15312            this.buffer.update(cx, |buffer, cx| {
15313                buffer.edit(
15314                    full_edits
15315                        .iter()
15316                        .map(|(_, p, t)| (p.clone(), t.clone()))
15317                        .collect::<Vec<_>>(),
15318                    None,
15319                    cx,
15320                );
15321            });
15322            this.change_selections(Default::default(), window, cx, |s| {
15323                let mut offset = 0;
15324                let mut selections = vec![];
15325                for (id, parent, text) in full_edits {
15326                    let start = parent.start - offset;
15327                    offset += parent.len() - text.len();
15328                    selections.push(Selection {
15329                        id,
15330                        start,
15331                        end: start + text.len(),
15332                        reversed: false,
15333                        goal: Default::default(),
15334                    });
15335                }
15336                s.select(selections);
15337            });
15338        });
15339    }
15340
15341    pub fn select_next_syntax_node(
15342        &mut self,
15343        _: &SelectNextSyntaxNode,
15344        window: &mut Window,
15345        cx: &mut Context<Self>,
15346    ) {
15347        let old_selections: Box<[_]> = self
15348            .selections
15349            .all::<usize>(&self.display_snapshot(cx))
15350            .into();
15351        if old_selections.is_empty() {
15352            return;
15353        }
15354
15355        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15356
15357        let buffer = self.buffer.read(cx).snapshot(cx);
15358        let mut selected_sibling = false;
15359
15360        let new_selections = old_selections
15361            .iter()
15362            .map(|selection| {
15363                let old_range = selection.start..selection.end;
15364
15365                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15366                    let new_range = node.byte_range();
15367                    selected_sibling = true;
15368                    Selection {
15369                        id: selection.id,
15370                        start: new_range.start,
15371                        end: new_range.end,
15372                        goal: SelectionGoal::None,
15373                        reversed: selection.reversed,
15374                    }
15375                } else {
15376                    selection.clone()
15377                }
15378            })
15379            .collect::<Vec<_>>();
15380
15381        if selected_sibling {
15382            self.change_selections(
15383                SelectionEffects::scroll(Autoscroll::fit()),
15384                window,
15385                cx,
15386                |s| {
15387                    s.select(new_selections);
15388                },
15389            );
15390        }
15391    }
15392
15393    pub fn select_prev_syntax_node(
15394        &mut self,
15395        _: &SelectPreviousSyntaxNode,
15396        window: &mut Window,
15397        cx: &mut Context<Self>,
15398    ) {
15399        let old_selections: Box<[_]> = self
15400            .selections
15401            .all::<usize>(&self.display_snapshot(cx))
15402            .into();
15403        if old_selections.is_empty() {
15404            return;
15405        }
15406
15407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15408
15409        let buffer = self.buffer.read(cx).snapshot(cx);
15410        let mut selected_sibling = false;
15411
15412        let new_selections = old_selections
15413            .iter()
15414            .map(|selection| {
15415                let old_range = selection.start..selection.end;
15416
15417                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15418                    let new_range = node.byte_range();
15419                    selected_sibling = true;
15420                    Selection {
15421                        id: selection.id,
15422                        start: new_range.start,
15423                        end: new_range.end,
15424                        goal: SelectionGoal::None,
15425                        reversed: selection.reversed,
15426                    }
15427                } else {
15428                    selection.clone()
15429                }
15430            })
15431            .collect::<Vec<_>>();
15432
15433        if selected_sibling {
15434            self.change_selections(
15435                SelectionEffects::scroll(Autoscroll::fit()),
15436                window,
15437                cx,
15438                |s| {
15439                    s.select(new_selections);
15440                },
15441            );
15442        }
15443    }
15444
15445    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15446        if !EditorSettings::get_global(cx).gutter.runnables {
15447            self.clear_tasks();
15448            return Task::ready(());
15449        }
15450        let project = self.project().map(Entity::downgrade);
15451        let task_sources = self.lsp_task_sources(cx);
15452        let multi_buffer = self.buffer.downgrade();
15453        cx.spawn_in(window, async move |editor, cx| {
15454            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15455            let Some(project) = project.and_then(|p| p.upgrade()) else {
15456                return;
15457            };
15458            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15459                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15460            }) else {
15461                return;
15462            };
15463
15464            let hide_runnables = project
15465                .update(cx, |project, _| project.is_via_collab())
15466                .unwrap_or(true);
15467            if hide_runnables {
15468                return;
15469            }
15470            let new_rows =
15471                cx.background_spawn({
15472                    let snapshot = display_snapshot.clone();
15473                    async move {
15474                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15475                    }
15476                })
15477                    .await;
15478            let Ok(lsp_tasks) =
15479                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15480            else {
15481                return;
15482            };
15483            let lsp_tasks = lsp_tasks.await;
15484
15485            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15486                lsp_tasks
15487                    .into_iter()
15488                    .flat_map(|(kind, tasks)| {
15489                        tasks.into_iter().filter_map(move |(location, task)| {
15490                            Some((kind.clone(), location?, task))
15491                        })
15492                    })
15493                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15494                        let buffer = location.target.buffer;
15495                        let buffer_snapshot = buffer.read(cx).snapshot();
15496                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15497                            |(excerpt_id, snapshot, _)| {
15498                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15499                                    display_snapshot
15500                                        .buffer_snapshot()
15501                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15502                                } else {
15503                                    None
15504                                }
15505                            },
15506                        );
15507                        if let Some(offset) = offset {
15508                            let task_buffer_range =
15509                                location.target.range.to_point(&buffer_snapshot);
15510                            let context_buffer_range =
15511                                task_buffer_range.to_offset(&buffer_snapshot);
15512                            let context_range = BufferOffset(context_buffer_range.start)
15513                                ..BufferOffset(context_buffer_range.end);
15514
15515                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15516                                .or_insert_with(|| RunnableTasks {
15517                                    templates: Vec::new(),
15518                                    offset,
15519                                    column: task_buffer_range.start.column,
15520                                    extra_variables: HashMap::default(),
15521                                    context_range,
15522                                })
15523                                .templates
15524                                .push((kind, task.original_task().clone()));
15525                        }
15526
15527                        acc
15528                    })
15529            }) else {
15530                return;
15531            };
15532
15533            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15534                buffer.language_settings(cx).tasks.prefer_lsp
15535            }) else {
15536                return;
15537            };
15538
15539            let rows = Self::runnable_rows(
15540                project,
15541                display_snapshot,
15542                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15543                new_rows,
15544                cx.clone(),
15545            )
15546            .await;
15547            editor
15548                .update(cx, |editor, _| {
15549                    editor.clear_tasks();
15550                    for (key, mut value) in rows {
15551                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15552                            value.templates.extend(lsp_tasks.templates);
15553                        }
15554
15555                        editor.insert_tasks(key, value);
15556                    }
15557                    for (key, value) in lsp_tasks_by_rows {
15558                        editor.insert_tasks(key, value);
15559                    }
15560                })
15561                .ok();
15562        })
15563    }
15564    fn fetch_runnable_ranges(
15565        snapshot: &DisplaySnapshot,
15566        range: Range<Anchor>,
15567    ) -> Vec<language::RunnableRange> {
15568        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15569    }
15570
15571    fn runnable_rows(
15572        project: Entity<Project>,
15573        snapshot: DisplaySnapshot,
15574        prefer_lsp: bool,
15575        runnable_ranges: Vec<RunnableRange>,
15576        cx: AsyncWindowContext,
15577    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15578        cx.spawn(async move |cx| {
15579            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15580            for mut runnable in runnable_ranges {
15581                let Some(tasks) = cx
15582                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15583                    .ok()
15584                else {
15585                    continue;
15586                };
15587                let mut tasks = tasks.await;
15588
15589                if prefer_lsp {
15590                    tasks.retain(|(task_kind, _)| {
15591                        !matches!(task_kind, TaskSourceKind::Language { .. })
15592                    });
15593                }
15594                if tasks.is_empty() {
15595                    continue;
15596                }
15597
15598                let point = runnable
15599                    .run_range
15600                    .start
15601                    .to_point(&snapshot.buffer_snapshot());
15602                let Some(row) = snapshot
15603                    .buffer_snapshot()
15604                    .buffer_line_for_row(MultiBufferRow(point.row))
15605                    .map(|(_, range)| range.start.row)
15606                else {
15607                    continue;
15608                };
15609
15610                let context_range =
15611                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15612                runnable_rows.push((
15613                    (runnable.buffer_id, row),
15614                    RunnableTasks {
15615                        templates: tasks,
15616                        offset: snapshot
15617                            .buffer_snapshot()
15618                            .anchor_before(runnable.run_range.start),
15619                        context_range,
15620                        column: point.column,
15621                        extra_variables: runnable.extra_captures,
15622                    },
15623                ));
15624            }
15625            runnable_rows
15626        })
15627    }
15628
15629    fn templates_with_tags(
15630        project: &Entity<Project>,
15631        runnable: &mut Runnable,
15632        cx: &mut App,
15633    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15634        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15635            let (worktree_id, file) = project
15636                .buffer_for_id(runnable.buffer, cx)
15637                .and_then(|buffer| buffer.read(cx).file())
15638                .map(|file| (file.worktree_id(cx), file.clone()))
15639                .unzip();
15640
15641            (
15642                project.task_store().read(cx).task_inventory().cloned(),
15643                worktree_id,
15644                file,
15645            )
15646        });
15647
15648        let tags = mem::take(&mut runnable.tags);
15649        let language = runnable.language.clone();
15650        cx.spawn(async move |cx| {
15651            let mut templates_with_tags = Vec::new();
15652            if let Some(inventory) = inventory {
15653                for RunnableTag(tag) in tags {
15654                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15655                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15656                    }) else {
15657                        return templates_with_tags;
15658                    };
15659                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15660                        move |(_, template)| {
15661                            template.tags.iter().any(|source_tag| source_tag == &tag)
15662                        },
15663                    ));
15664                }
15665            }
15666            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15667
15668            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15669                // Strongest source wins; if we have worktree tag binding, prefer that to
15670                // global and language bindings;
15671                // if we have a global binding, prefer that to language binding.
15672                let first_mismatch = templates_with_tags
15673                    .iter()
15674                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15675                if let Some(index) = first_mismatch {
15676                    templates_with_tags.truncate(index);
15677                }
15678            }
15679
15680            templates_with_tags
15681        })
15682    }
15683
15684    pub fn move_to_enclosing_bracket(
15685        &mut self,
15686        _: &MoveToEnclosingBracket,
15687        window: &mut Window,
15688        cx: &mut Context<Self>,
15689    ) {
15690        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15691        self.change_selections(Default::default(), window, cx, |s| {
15692            s.move_offsets_with(|snapshot, selection| {
15693                let Some(enclosing_bracket_ranges) =
15694                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15695                else {
15696                    return;
15697                };
15698
15699                let mut best_length = usize::MAX;
15700                let mut best_inside = false;
15701                let mut best_in_bracket_range = false;
15702                let mut best_destination = None;
15703                for (open, close) in enclosing_bracket_ranges {
15704                    let close = close.to_inclusive();
15705                    let length = close.end() - open.start;
15706                    let inside = selection.start >= open.end && selection.end <= *close.start();
15707                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15708                        || close.contains(&selection.head());
15709
15710                    // If best is next to a bracket and current isn't, skip
15711                    if !in_bracket_range && best_in_bracket_range {
15712                        continue;
15713                    }
15714
15715                    // Prefer smaller lengths unless best is inside and current isn't
15716                    if length > best_length && (best_inside || !inside) {
15717                        continue;
15718                    }
15719
15720                    best_length = length;
15721                    best_inside = inside;
15722                    best_in_bracket_range = in_bracket_range;
15723                    best_destination = Some(
15724                        if close.contains(&selection.start) && close.contains(&selection.end) {
15725                            if inside { open.end } else { open.start }
15726                        } else if inside {
15727                            *close.start()
15728                        } else {
15729                            *close.end()
15730                        },
15731                    );
15732                }
15733
15734                if let Some(destination) = best_destination {
15735                    selection.collapse_to(destination, SelectionGoal::None);
15736                }
15737            })
15738        });
15739    }
15740
15741    pub fn undo_selection(
15742        &mut self,
15743        _: &UndoSelection,
15744        window: &mut Window,
15745        cx: &mut Context<Self>,
15746    ) {
15747        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15748        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15749            self.selection_history.mode = SelectionHistoryMode::Undoing;
15750            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15751                this.end_selection(window, cx);
15752                this.change_selections(
15753                    SelectionEffects::scroll(Autoscroll::newest()),
15754                    window,
15755                    cx,
15756                    |s| s.select_anchors(entry.selections.to_vec()),
15757                );
15758            });
15759            self.selection_history.mode = SelectionHistoryMode::Normal;
15760
15761            self.select_next_state = entry.select_next_state;
15762            self.select_prev_state = entry.select_prev_state;
15763            self.add_selections_state = entry.add_selections_state;
15764        }
15765    }
15766
15767    pub fn redo_selection(
15768        &mut self,
15769        _: &RedoSelection,
15770        window: &mut Window,
15771        cx: &mut Context<Self>,
15772    ) {
15773        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15774        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15775            self.selection_history.mode = SelectionHistoryMode::Redoing;
15776            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15777                this.end_selection(window, cx);
15778                this.change_selections(
15779                    SelectionEffects::scroll(Autoscroll::newest()),
15780                    window,
15781                    cx,
15782                    |s| s.select_anchors(entry.selections.to_vec()),
15783                );
15784            });
15785            self.selection_history.mode = SelectionHistoryMode::Normal;
15786
15787            self.select_next_state = entry.select_next_state;
15788            self.select_prev_state = entry.select_prev_state;
15789            self.add_selections_state = entry.add_selections_state;
15790        }
15791    }
15792
15793    pub fn expand_excerpts(
15794        &mut self,
15795        action: &ExpandExcerpts,
15796        _: &mut Window,
15797        cx: &mut Context<Self>,
15798    ) {
15799        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15800    }
15801
15802    pub fn expand_excerpts_down(
15803        &mut self,
15804        action: &ExpandExcerptsDown,
15805        _: &mut Window,
15806        cx: &mut Context<Self>,
15807    ) {
15808        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15809    }
15810
15811    pub fn expand_excerpts_up(
15812        &mut self,
15813        action: &ExpandExcerptsUp,
15814        _: &mut Window,
15815        cx: &mut Context<Self>,
15816    ) {
15817        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15818    }
15819
15820    pub fn expand_excerpts_for_direction(
15821        &mut self,
15822        lines: u32,
15823        direction: ExpandExcerptDirection,
15824
15825        cx: &mut Context<Self>,
15826    ) {
15827        let selections = self.selections.disjoint_anchors_arc();
15828
15829        let lines = if lines == 0 {
15830            EditorSettings::get_global(cx).expand_excerpt_lines
15831        } else {
15832            lines
15833        };
15834
15835        self.buffer.update(cx, |buffer, cx| {
15836            let snapshot = buffer.snapshot(cx);
15837            let mut excerpt_ids = selections
15838                .iter()
15839                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15840                .collect::<Vec<_>>();
15841            excerpt_ids.sort();
15842            excerpt_ids.dedup();
15843            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15844        })
15845    }
15846
15847    pub fn expand_excerpt(
15848        &mut self,
15849        excerpt: ExcerptId,
15850        direction: ExpandExcerptDirection,
15851        window: &mut Window,
15852        cx: &mut Context<Self>,
15853    ) {
15854        let current_scroll_position = self.scroll_position(cx);
15855        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15856        let mut should_scroll_up = false;
15857
15858        if direction == ExpandExcerptDirection::Down {
15859            let multi_buffer = self.buffer.read(cx);
15860            let snapshot = multi_buffer.snapshot(cx);
15861            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15862                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15863                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15864            {
15865                let buffer_snapshot = buffer.read(cx).snapshot();
15866                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15867                let last_row = buffer_snapshot.max_point().row;
15868                let lines_below = last_row.saturating_sub(excerpt_end_row);
15869                should_scroll_up = lines_below >= lines_to_expand;
15870            }
15871        }
15872
15873        self.buffer.update(cx, |buffer, cx| {
15874            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15875        });
15876
15877        if should_scroll_up {
15878            let new_scroll_position =
15879                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15880            self.set_scroll_position(new_scroll_position, window, cx);
15881        }
15882    }
15883
15884    pub fn go_to_singleton_buffer_point(
15885        &mut self,
15886        point: Point,
15887        window: &mut Window,
15888        cx: &mut Context<Self>,
15889    ) {
15890        self.go_to_singleton_buffer_range(point..point, window, cx);
15891    }
15892
15893    pub fn go_to_singleton_buffer_range(
15894        &mut self,
15895        range: Range<Point>,
15896        window: &mut Window,
15897        cx: &mut Context<Self>,
15898    ) {
15899        let multibuffer = self.buffer().read(cx);
15900        let Some(buffer) = multibuffer.as_singleton() else {
15901            return;
15902        };
15903        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15904            return;
15905        };
15906        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15907            return;
15908        };
15909        self.change_selections(
15910            SelectionEffects::default().nav_history(true),
15911            window,
15912            cx,
15913            |s| s.select_anchor_ranges([start..end]),
15914        );
15915    }
15916
15917    pub fn go_to_diagnostic(
15918        &mut self,
15919        action: &GoToDiagnostic,
15920        window: &mut Window,
15921        cx: &mut Context<Self>,
15922    ) {
15923        if !self.diagnostics_enabled() {
15924            return;
15925        }
15926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15927        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15928    }
15929
15930    pub fn go_to_prev_diagnostic(
15931        &mut self,
15932        action: &GoToPreviousDiagnostic,
15933        window: &mut Window,
15934        cx: &mut Context<Self>,
15935    ) {
15936        if !self.diagnostics_enabled() {
15937            return;
15938        }
15939        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15940        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15941    }
15942
15943    pub fn go_to_diagnostic_impl(
15944        &mut self,
15945        direction: Direction,
15946        severity: GoToDiagnosticSeverityFilter,
15947        window: &mut Window,
15948        cx: &mut Context<Self>,
15949    ) {
15950        let buffer = self.buffer.read(cx).snapshot(cx);
15951        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
15952
15953        let mut active_group_id = None;
15954        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15955            && active_group.active_range.start.to_offset(&buffer) == selection.start
15956        {
15957            active_group_id = Some(active_group.group_id);
15958        }
15959
15960        fn filtered<'a>(
15961            snapshot: EditorSnapshot,
15962            severity: GoToDiagnosticSeverityFilter,
15963            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
15964        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
15965            diagnostics
15966                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15967                .filter(|entry| entry.range.start != entry.range.end)
15968                .filter(|entry| !entry.diagnostic.is_unnecessary)
15969                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15970        }
15971
15972        let snapshot = self.snapshot(window, cx);
15973        let before = filtered(
15974            snapshot.clone(),
15975            severity,
15976            buffer
15977                .diagnostics_in_range(0..selection.start)
15978                .filter(|entry| entry.range.start <= selection.start),
15979        );
15980        let after = filtered(
15981            snapshot,
15982            severity,
15983            buffer
15984                .diagnostics_in_range(selection.start..buffer.len())
15985                .filter(|entry| entry.range.start >= selection.start),
15986        );
15987
15988        let mut found: Option<DiagnosticEntryRef<usize>> = None;
15989        if direction == Direction::Prev {
15990            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15991            {
15992                for diagnostic in prev_diagnostics.into_iter().rev() {
15993                    if diagnostic.range.start != selection.start
15994                        || active_group_id
15995                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15996                    {
15997                        found = Some(diagnostic);
15998                        break 'outer;
15999                    }
16000                }
16001            }
16002        } else {
16003            for diagnostic in after.chain(before) {
16004                if diagnostic.range.start != selection.start
16005                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16006                {
16007                    found = Some(diagnostic);
16008                    break;
16009                }
16010            }
16011        }
16012        let Some(next_diagnostic) = found else {
16013            return;
16014        };
16015
16016        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16017        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16018            return;
16019        };
16020        self.change_selections(Default::default(), window, cx, |s| {
16021            s.select_ranges(vec![
16022                next_diagnostic.range.start..next_diagnostic.range.start,
16023            ])
16024        });
16025        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16026        self.refresh_edit_prediction(false, true, window, cx);
16027    }
16028
16029    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16030        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16031        let snapshot = self.snapshot(window, cx);
16032        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16033        self.go_to_hunk_before_or_after_position(
16034            &snapshot,
16035            selection.head(),
16036            Direction::Next,
16037            window,
16038            cx,
16039        );
16040    }
16041
16042    pub fn go_to_hunk_before_or_after_position(
16043        &mut self,
16044        snapshot: &EditorSnapshot,
16045        position: Point,
16046        direction: Direction,
16047        window: &mut Window,
16048        cx: &mut Context<Editor>,
16049    ) {
16050        let row = if direction == Direction::Next {
16051            self.hunk_after_position(snapshot, position)
16052                .map(|hunk| hunk.row_range.start)
16053        } else {
16054            self.hunk_before_position(snapshot, position)
16055        };
16056
16057        if let Some(row) = row {
16058            let destination = Point::new(row.0, 0);
16059            let autoscroll = Autoscroll::center();
16060
16061            self.unfold_ranges(&[destination..destination], false, false, cx);
16062            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16063                s.select_ranges([destination..destination]);
16064            });
16065        }
16066    }
16067
16068    fn hunk_after_position(
16069        &mut self,
16070        snapshot: &EditorSnapshot,
16071        position: Point,
16072    ) -> Option<MultiBufferDiffHunk> {
16073        snapshot
16074            .buffer_snapshot()
16075            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16076            .find(|hunk| hunk.row_range.start.0 > position.row)
16077            .or_else(|| {
16078                snapshot
16079                    .buffer_snapshot()
16080                    .diff_hunks_in_range(Point::zero()..position)
16081                    .find(|hunk| hunk.row_range.end.0 < position.row)
16082            })
16083    }
16084
16085    fn go_to_prev_hunk(
16086        &mut self,
16087        _: &GoToPreviousHunk,
16088        window: &mut Window,
16089        cx: &mut Context<Self>,
16090    ) {
16091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16092        let snapshot = self.snapshot(window, cx);
16093        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16094        self.go_to_hunk_before_or_after_position(
16095            &snapshot,
16096            selection.head(),
16097            Direction::Prev,
16098            window,
16099            cx,
16100        );
16101    }
16102
16103    fn hunk_before_position(
16104        &mut self,
16105        snapshot: &EditorSnapshot,
16106        position: Point,
16107    ) -> Option<MultiBufferRow> {
16108        snapshot
16109            .buffer_snapshot()
16110            .diff_hunk_before(position)
16111            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16112    }
16113
16114    fn go_to_next_change(
16115        &mut self,
16116        _: &GoToNextChange,
16117        window: &mut Window,
16118        cx: &mut Context<Self>,
16119    ) {
16120        if let Some(selections) = self
16121            .change_list
16122            .next_change(1, Direction::Next)
16123            .map(|s| s.to_vec())
16124        {
16125            self.change_selections(Default::default(), window, cx, |s| {
16126                let map = s.display_map();
16127                s.select_display_ranges(selections.iter().map(|a| {
16128                    let point = a.to_display_point(&map);
16129                    point..point
16130                }))
16131            })
16132        }
16133    }
16134
16135    fn go_to_previous_change(
16136        &mut self,
16137        _: &GoToPreviousChange,
16138        window: &mut Window,
16139        cx: &mut Context<Self>,
16140    ) {
16141        if let Some(selections) = self
16142            .change_list
16143            .next_change(1, Direction::Prev)
16144            .map(|s| s.to_vec())
16145        {
16146            self.change_selections(Default::default(), window, cx, |s| {
16147                let map = s.display_map();
16148                s.select_display_ranges(selections.iter().map(|a| {
16149                    let point = a.to_display_point(&map);
16150                    point..point
16151                }))
16152            })
16153        }
16154    }
16155
16156    pub fn go_to_next_document_highlight(
16157        &mut self,
16158        _: &GoToNextDocumentHighlight,
16159        window: &mut Window,
16160        cx: &mut Context<Self>,
16161    ) {
16162        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16163    }
16164
16165    pub fn go_to_prev_document_highlight(
16166        &mut self,
16167        _: &GoToPreviousDocumentHighlight,
16168        window: &mut Window,
16169        cx: &mut Context<Self>,
16170    ) {
16171        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16172    }
16173
16174    pub fn go_to_document_highlight_before_or_after_position(
16175        &mut self,
16176        direction: Direction,
16177        window: &mut Window,
16178        cx: &mut Context<Editor>,
16179    ) {
16180        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16181        let snapshot = self.snapshot(window, cx);
16182        let buffer = &snapshot.buffer_snapshot();
16183        let position = self
16184            .selections
16185            .newest::<Point>(&snapshot.display_snapshot)
16186            .head();
16187        let anchor_position = buffer.anchor_after(position);
16188
16189        // Get all document highlights (both read and write)
16190        let mut all_highlights = Vec::new();
16191
16192        if let Some((_, read_highlights)) = self
16193            .background_highlights
16194            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16195        {
16196            all_highlights.extend(read_highlights.iter());
16197        }
16198
16199        if let Some((_, write_highlights)) = self
16200            .background_highlights
16201            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16202        {
16203            all_highlights.extend(write_highlights.iter());
16204        }
16205
16206        if all_highlights.is_empty() {
16207            return;
16208        }
16209
16210        // Sort highlights by position
16211        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16212
16213        let target_highlight = match direction {
16214            Direction::Next => {
16215                // Find the first highlight after the current position
16216                all_highlights
16217                    .iter()
16218                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16219            }
16220            Direction::Prev => {
16221                // Find the last highlight before the current position
16222                all_highlights
16223                    .iter()
16224                    .rev()
16225                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16226            }
16227        };
16228
16229        if let Some(highlight) = target_highlight {
16230            let destination = highlight.start.to_point(buffer);
16231            let autoscroll = Autoscroll::center();
16232
16233            self.unfold_ranges(&[destination..destination], false, false, cx);
16234            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16235                s.select_ranges([destination..destination]);
16236            });
16237        }
16238    }
16239
16240    fn go_to_line<T: 'static>(
16241        &mut self,
16242        position: Anchor,
16243        highlight_color: Option<Hsla>,
16244        window: &mut Window,
16245        cx: &mut Context<Self>,
16246    ) {
16247        let snapshot = self.snapshot(window, cx).display_snapshot;
16248        let position = position.to_point(&snapshot.buffer_snapshot());
16249        let start = snapshot
16250            .buffer_snapshot()
16251            .clip_point(Point::new(position.row, 0), Bias::Left);
16252        let end = start + Point::new(1, 0);
16253        let start = snapshot.buffer_snapshot().anchor_before(start);
16254        let end = snapshot.buffer_snapshot().anchor_before(end);
16255
16256        self.highlight_rows::<T>(
16257            start..end,
16258            highlight_color
16259                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16260            Default::default(),
16261            cx,
16262        );
16263
16264        if self.buffer.read(cx).is_singleton() {
16265            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16266        }
16267    }
16268
16269    pub fn go_to_definition(
16270        &mut self,
16271        _: &GoToDefinition,
16272        window: &mut Window,
16273        cx: &mut Context<Self>,
16274    ) -> Task<Result<Navigated>> {
16275        let definition =
16276            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16277        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16278        cx.spawn_in(window, async move |editor, cx| {
16279            if definition.await? == Navigated::Yes {
16280                return Ok(Navigated::Yes);
16281            }
16282            match fallback_strategy {
16283                GoToDefinitionFallback::None => Ok(Navigated::No),
16284                GoToDefinitionFallback::FindAllReferences => {
16285                    match editor.update_in(cx, |editor, window, cx| {
16286                        editor.find_all_references(&FindAllReferences, window, cx)
16287                    })? {
16288                        Some(references) => references.await,
16289                        None => Ok(Navigated::No),
16290                    }
16291                }
16292            }
16293        })
16294    }
16295
16296    pub fn go_to_declaration(
16297        &mut self,
16298        _: &GoToDeclaration,
16299        window: &mut Window,
16300        cx: &mut Context<Self>,
16301    ) -> Task<Result<Navigated>> {
16302        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16303    }
16304
16305    pub fn go_to_declaration_split(
16306        &mut self,
16307        _: &GoToDeclaration,
16308        window: &mut Window,
16309        cx: &mut Context<Self>,
16310    ) -> Task<Result<Navigated>> {
16311        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16312    }
16313
16314    pub fn go_to_implementation(
16315        &mut self,
16316        _: &GoToImplementation,
16317        window: &mut Window,
16318        cx: &mut Context<Self>,
16319    ) -> Task<Result<Navigated>> {
16320        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16321    }
16322
16323    pub fn go_to_implementation_split(
16324        &mut self,
16325        _: &GoToImplementationSplit,
16326        window: &mut Window,
16327        cx: &mut Context<Self>,
16328    ) -> Task<Result<Navigated>> {
16329        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16330    }
16331
16332    pub fn go_to_type_definition(
16333        &mut self,
16334        _: &GoToTypeDefinition,
16335        window: &mut Window,
16336        cx: &mut Context<Self>,
16337    ) -> Task<Result<Navigated>> {
16338        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16339    }
16340
16341    pub fn go_to_definition_split(
16342        &mut self,
16343        _: &GoToDefinitionSplit,
16344        window: &mut Window,
16345        cx: &mut Context<Self>,
16346    ) -> Task<Result<Navigated>> {
16347        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16348    }
16349
16350    pub fn go_to_type_definition_split(
16351        &mut self,
16352        _: &GoToTypeDefinitionSplit,
16353        window: &mut Window,
16354        cx: &mut Context<Self>,
16355    ) -> Task<Result<Navigated>> {
16356        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16357    }
16358
16359    fn go_to_definition_of_kind(
16360        &mut self,
16361        kind: GotoDefinitionKind,
16362        split: bool,
16363        window: &mut Window,
16364        cx: &mut Context<Self>,
16365    ) -> Task<Result<Navigated>> {
16366        let Some(provider) = self.semantics_provider.clone() else {
16367            return Task::ready(Ok(Navigated::No));
16368        };
16369        let head = self
16370            .selections
16371            .newest::<usize>(&self.display_snapshot(cx))
16372            .head();
16373        let buffer = self.buffer.read(cx);
16374        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16375            return Task::ready(Ok(Navigated::No));
16376        };
16377        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16378            return Task::ready(Ok(Navigated::No));
16379        };
16380
16381        cx.spawn_in(window, async move |editor, cx| {
16382            let Some(definitions) = definitions.await? else {
16383                return Ok(Navigated::No);
16384            };
16385            let navigated = editor
16386                .update_in(cx, |editor, window, cx| {
16387                    editor.navigate_to_hover_links(
16388                        Some(kind),
16389                        definitions
16390                            .into_iter()
16391                            .filter(|location| {
16392                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16393                            })
16394                            .map(HoverLink::Text)
16395                            .collect::<Vec<_>>(),
16396                        split,
16397                        window,
16398                        cx,
16399                    )
16400                })?
16401                .await?;
16402            anyhow::Ok(navigated)
16403        })
16404    }
16405
16406    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16407        let selection = self.selections.newest_anchor();
16408        let head = selection.head();
16409        let tail = selection.tail();
16410
16411        let Some((buffer, start_position)) =
16412            self.buffer.read(cx).text_anchor_for_position(head, cx)
16413        else {
16414            return;
16415        };
16416
16417        let end_position = if head != tail {
16418            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16419                return;
16420            };
16421            Some(pos)
16422        } else {
16423            None
16424        };
16425
16426        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16427            let url = if let Some(end_pos) = end_position {
16428                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16429            } else {
16430                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16431            };
16432
16433            if let Some(url) = url {
16434                cx.update(|window, cx| {
16435                    if parse_zed_link(&url, cx).is_some() {
16436                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16437                    } else {
16438                        cx.open_url(&url);
16439                    }
16440                })?;
16441            }
16442
16443            anyhow::Ok(())
16444        });
16445
16446        url_finder.detach();
16447    }
16448
16449    pub fn open_selected_filename(
16450        &mut self,
16451        _: &OpenSelectedFilename,
16452        window: &mut Window,
16453        cx: &mut Context<Self>,
16454    ) {
16455        let Some(workspace) = self.workspace() else {
16456            return;
16457        };
16458
16459        let position = self.selections.newest_anchor().head();
16460
16461        let Some((buffer, buffer_position)) =
16462            self.buffer.read(cx).text_anchor_for_position(position, cx)
16463        else {
16464            return;
16465        };
16466
16467        let project = self.project.clone();
16468
16469        cx.spawn_in(window, async move |_, cx| {
16470            let result = find_file(&buffer, project, buffer_position, cx).await;
16471
16472            if let Some((_, path)) = result {
16473                workspace
16474                    .update_in(cx, |workspace, window, cx| {
16475                        workspace.open_resolved_path(path, window, cx)
16476                    })?
16477                    .await?;
16478            }
16479            anyhow::Ok(())
16480        })
16481        .detach();
16482    }
16483
16484    pub(crate) fn navigate_to_hover_links(
16485        &mut self,
16486        kind: Option<GotoDefinitionKind>,
16487        definitions: Vec<HoverLink>,
16488        split: bool,
16489        window: &mut Window,
16490        cx: &mut Context<Editor>,
16491    ) -> Task<Result<Navigated>> {
16492        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16493        let mut first_url_or_file = None;
16494        let definitions: Vec<_> = definitions
16495            .into_iter()
16496            .filter_map(|def| match def {
16497                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16498                HoverLink::InlayHint(lsp_location, server_id) => {
16499                    let computation =
16500                        self.compute_target_location(lsp_location, server_id, window, cx);
16501                    Some(cx.background_spawn(computation))
16502                }
16503                HoverLink::Url(url) => {
16504                    first_url_or_file = Some(Either::Left(url));
16505                    None
16506                }
16507                HoverLink::File(path) => {
16508                    first_url_or_file = Some(Either::Right(path));
16509                    None
16510                }
16511            })
16512            .collect();
16513
16514        let workspace = self.workspace();
16515
16516        cx.spawn_in(window, async move |editor, cx| {
16517            let locations: Vec<Location> = future::join_all(definitions)
16518                .await
16519                .into_iter()
16520                .filter_map(|location| location.transpose())
16521                .collect::<Result<_>>()
16522                .context("location tasks")?;
16523            let mut locations = cx.update(|_, cx| {
16524                locations
16525                    .into_iter()
16526                    .map(|location| {
16527                        let buffer = location.buffer.read(cx);
16528                        (location.buffer, location.range.to_point(buffer))
16529                    })
16530                    .into_group_map()
16531            })?;
16532            let mut num_locations = 0;
16533            for ranges in locations.values_mut() {
16534                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16535                ranges.dedup();
16536                num_locations += ranges.len();
16537            }
16538
16539            if num_locations > 1 {
16540                let Some(workspace) = workspace else {
16541                    return Ok(Navigated::No);
16542                };
16543
16544                let tab_kind = match kind {
16545                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16546                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16547                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16548                    Some(GotoDefinitionKind::Type) => "Types",
16549                };
16550                let title = editor
16551                    .update_in(cx, |_, _, cx| {
16552                        let target = locations
16553                            .iter()
16554                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16555                            .map(|(buffer, location)| {
16556                                buffer
16557                                    .read(cx)
16558                                    .text_for_range(location.clone())
16559                                    .collect::<String>()
16560                            })
16561                            .filter(|text| !text.contains('\n'))
16562                            .unique()
16563                            .take(3)
16564                            .join(", ");
16565                        if target.is_empty() {
16566                            tab_kind.to_owned()
16567                        } else {
16568                            format!("{tab_kind} for {target}")
16569                        }
16570                    })
16571                    .context("buffer title")?;
16572
16573                let opened = workspace
16574                    .update_in(cx, |workspace, window, cx| {
16575                        Self::open_locations_in_multibuffer(
16576                            workspace,
16577                            locations,
16578                            title,
16579                            split,
16580                            MultibufferSelectionMode::First,
16581                            window,
16582                            cx,
16583                        )
16584                    })
16585                    .is_ok();
16586
16587                anyhow::Ok(Navigated::from_bool(opened))
16588            } else if num_locations == 0 {
16589                // If there is one url or file, open it directly
16590                match first_url_or_file {
16591                    Some(Either::Left(url)) => {
16592                        cx.update(|_, cx| cx.open_url(&url))?;
16593                        Ok(Navigated::Yes)
16594                    }
16595                    Some(Either::Right(path)) => {
16596                        let Some(workspace) = workspace else {
16597                            return Ok(Navigated::No);
16598                        };
16599
16600                        workspace
16601                            .update_in(cx, |workspace, window, cx| {
16602                                workspace.open_resolved_path(path, window, cx)
16603                            })?
16604                            .await?;
16605                        Ok(Navigated::Yes)
16606                    }
16607                    None => Ok(Navigated::No),
16608                }
16609            } else {
16610                let Some(workspace) = workspace else {
16611                    return Ok(Navigated::No);
16612                };
16613
16614                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16615                let target_range = target_ranges.first().unwrap().clone();
16616
16617                editor.update_in(cx, |editor, window, cx| {
16618                    let range = target_range.to_point(target_buffer.read(cx));
16619                    let range = editor.range_for_match(&range);
16620                    let range = collapse_multiline_range(range);
16621
16622                    if !split
16623                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16624                    {
16625                        editor.go_to_singleton_buffer_range(range, window, cx);
16626                    } else {
16627                        let pane = workspace.read(cx).active_pane().clone();
16628                        window.defer(cx, move |window, cx| {
16629                            let target_editor: Entity<Self> =
16630                                workspace.update(cx, |workspace, cx| {
16631                                    let pane = if split {
16632                                        workspace.adjacent_pane(window, cx)
16633                                    } else {
16634                                        workspace.active_pane().clone()
16635                                    };
16636
16637                                    workspace.open_project_item(
16638                                        pane,
16639                                        target_buffer.clone(),
16640                                        true,
16641                                        true,
16642                                        window,
16643                                        cx,
16644                                    )
16645                                });
16646                            target_editor.update(cx, |target_editor, cx| {
16647                                // When selecting a definition in a different buffer, disable the nav history
16648                                // to avoid creating a history entry at the previous cursor location.
16649                                pane.update(cx, |pane, _| pane.disable_history());
16650                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16651                                pane.update(cx, |pane, _| pane.enable_history());
16652                            });
16653                        });
16654                    }
16655                    Navigated::Yes
16656                })
16657            }
16658        })
16659    }
16660
16661    fn compute_target_location(
16662        &self,
16663        lsp_location: lsp::Location,
16664        server_id: LanguageServerId,
16665        window: &mut Window,
16666        cx: &mut Context<Self>,
16667    ) -> Task<anyhow::Result<Option<Location>>> {
16668        let Some(project) = self.project.clone() else {
16669            return Task::ready(Ok(None));
16670        };
16671
16672        cx.spawn_in(window, async move |editor, cx| {
16673            let location_task = editor.update(cx, |_, cx| {
16674                project.update(cx, |project, cx| {
16675                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16676                })
16677            })?;
16678            let location = Some({
16679                let target_buffer_handle = location_task.await.context("open local buffer")?;
16680                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16681                    let target_start = target_buffer
16682                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16683                    let target_end = target_buffer
16684                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16685                    target_buffer.anchor_after(target_start)
16686                        ..target_buffer.anchor_before(target_end)
16687                })?;
16688                Location {
16689                    buffer: target_buffer_handle,
16690                    range,
16691                }
16692            });
16693            Ok(location)
16694        })
16695    }
16696
16697    pub fn find_all_references(
16698        &mut self,
16699        _: &FindAllReferences,
16700        window: &mut Window,
16701        cx: &mut Context<Self>,
16702    ) -> Option<Task<Result<Navigated>>> {
16703        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16704        let multi_buffer = self.buffer.read(cx);
16705        let head = selection.head();
16706
16707        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16708        let head_anchor = multi_buffer_snapshot.anchor_at(
16709            head,
16710            if head < selection.tail() {
16711                Bias::Right
16712            } else {
16713                Bias::Left
16714            },
16715        );
16716
16717        match self
16718            .find_all_references_task_sources
16719            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16720        {
16721            Ok(_) => {
16722                log::info!(
16723                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16724                );
16725                return None;
16726            }
16727            Err(i) => {
16728                self.find_all_references_task_sources.insert(i, head_anchor);
16729            }
16730        }
16731
16732        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16733        let workspace = self.workspace()?;
16734        let project = workspace.read(cx).project().clone();
16735        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16736        Some(cx.spawn_in(window, async move |editor, cx| {
16737            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16738                if let Ok(i) = editor
16739                    .find_all_references_task_sources
16740                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16741                {
16742                    editor.find_all_references_task_sources.remove(i);
16743                }
16744            });
16745
16746            let Some(locations) = references.await? else {
16747                return anyhow::Ok(Navigated::No);
16748            };
16749            let mut locations = cx.update(|_, cx| {
16750                locations
16751                    .into_iter()
16752                    .map(|location| {
16753                        let buffer = location.buffer.read(cx);
16754                        (location.buffer, location.range.to_point(buffer))
16755                    })
16756                    .into_group_map()
16757            })?;
16758            if locations.is_empty() {
16759                return anyhow::Ok(Navigated::No);
16760            }
16761            for ranges in locations.values_mut() {
16762                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16763                ranges.dedup();
16764            }
16765
16766            workspace.update_in(cx, |workspace, window, cx| {
16767                let target = locations
16768                    .iter()
16769                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16770                    .map(|(buffer, location)| {
16771                        buffer
16772                            .read(cx)
16773                            .text_for_range(location.clone())
16774                            .collect::<String>()
16775                    })
16776                    .filter(|text| !text.contains('\n'))
16777                    .unique()
16778                    .take(3)
16779                    .join(", ");
16780                let title = if target.is_empty() {
16781                    "References".to_owned()
16782                } else {
16783                    format!("References to {target}")
16784                };
16785                Self::open_locations_in_multibuffer(
16786                    workspace,
16787                    locations,
16788                    title,
16789                    false,
16790                    MultibufferSelectionMode::First,
16791                    window,
16792                    cx,
16793                );
16794                Navigated::Yes
16795            })
16796        }))
16797    }
16798
16799    /// Opens a multibuffer with the given project locations in it
16800    pub fn open_locations_in_multibuffer(
16801        workspace: &mut Workspace,
16802        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16803        title: String,
16804        split: bool,
16805        multibuffer_selection_mode: MultibufferSelectionMode,
16806        window: &mut Window,
16807        cx: &mut Context<Workspace>,
16808    ) {
16809        if locations.is_empty() {
16810            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16811            return;
16812        }
16813
16814        let capability = workspace.project().read(cx).capability();
16815        let mut ranges = <Vec<Range<Anchor>>>::new();
16816
16817        // a key to find existing multibuffer editors with the same set of locations
16818        // to prevent us from opening more and more multibuffer tabs for searches and the like
16819        let mut key = (title.clone(), vec![]);
16820        let excerpt_buffer = cx.new(|cx| {
16821            let key = &mut key.1;
16822            let mut multibuffer = MultiBuffer::new(capability);
16823            for (buffer, mut ranges_for_buffer) in locations {
16824                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16825                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16826                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16827                    PathKey::for_buffer(&buffer, cx),
16828                    buffer.clone(),
16829                    ranges_for_buffer,
16830                    multibuffer_context_lines(cx),
16831                    cx,
16832                );
16833                ranges.extend(new_ranges)
16834            }
16835
16836            multibuffer.with_title(title)
16837        });
16838        let existing = workspace.active_pane().update(cx, |pane, cx| {
16839            pane.items()
16840                .filter_map(|item| item.downcast::<Editor>())
16841                .find(|editor| {
16842                    editor
16843                        .read(cx)
16844                        .lookup_key
16845                        .as_ref()
16846                        .and_then(|it| {
16847                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16848                        })
16849                        .is_some_and(|it| *it == key)
16850                })
16851        });
16852        let editor = existing.unwrap_or_else(|| {
16853            cx.new(|cx| {
16854                let mut editor = Editor::for_multibuffer(
16855                    excerpt_buffer,
16856                    Some(workspace.project().clone()),
16857                    window,
16858                    cx,
16859                );
16860                editor.lookup_key = Some(Box::new(key));
16861                editor
16862            })
16863        });
16864        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
16865            MultibufferSelectionMode::First => {
16866                if let Some(first_range) = ranges.first() {
16867                    editor.change_selections(
16868                        SelectionEffects::no_scroll(),
16869                        window,
16870                        cx,
16871                        |selections| {
16872                            selections.clear_disjoint();
16873                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
16874                        },
16875                    );
16876                }
16877                editor.highlight_background::<Self>(
16878                    &ranges,
16879                    |theme| theme.colors().editor_highlighted_line_background,
16880                    cx,
16881                );
16882            }
16883            MultibufferSelectionMode::All => {
16884                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
16885                    selections.clear_disjoint();
16886                    selections.select_anchor_ranges(ranges);
16887                });
16888            }
16889        });
16890
16891        let item = Box::new(editor);
16892        let item_id = item.item_id();
16893
16894        if split {
16895            let pane = workspace.adjacent_pane(window, cx);
16896            workspace.add_item(pane, item, None, true, true, window, cx);
16897        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16898            let (preview_item_id, preview_item_idx) =
16899                workspace.active_pane().read_with(cx, |pane, _| {
16900                    (pane.preview_item_id(), pane.preview_item_idx())
16901                });
16902
16903            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16904
16905            if let Some(preview_item_id) = preview_item_id {
16906                workspace.active_pane().update(cx, |pane, cx| {
16907                    pane.remove_item(preview_item_id, false, false, window, cx);
16908                });
16909            }
16910        } else {
16911            workspace.add_item_to_active_pane(item, None, true, window, cx);
16912        }
16913        workspace.active_pane().update(cx, |pane, cx| {
16914            pane.set_preview_item_id(Some(item_id), cx);
16915        });
16916    }
16917
16918    pub fn rename(
16919        &mut self,
16920        _: &Rename,
16921        window: &mut Window,
16922        cx: &mut Context<Self>,
16923    ) -> Option<Task<Result<()>>> {
16924        use language::ToOffset as _;
16925
16926        let provider = self.semantics_provider.clone()?;
16927        let selection = self.selections.newest_anchor().clone();
16928        let (cursor_buffer, cursor_buffer_position) = self
16929            .buffer
16930            .read(cx)
16931            .text_anchor_for_position(selection.head(), cx)?;
16932        let (tail_buffer, cursor_buffer_position_end) = self
16933            .buffer
16934            .read(cx)
16935            .text_anchor_for_position(selection.tail(), cx)?;
16936        if tail_buffer != cursor_buffer {
16937            return None;
16938        }
16939
16940        let snapshot = cursor_buffer.read(cx).snapshot();
16941        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16942        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16943        let prepare_rename = provider
16944            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16945            .unwrap_or_else(|| Task::ready(Ok(None)));
16946        drop(snapshot);
16947
16948        Some(cx.spawn_in(window, async move |this, cx| {
16949            let rename_range = if let Some(range) = prepare_rename.await? {
16950                Some(range)
16951            } else {
16952                this.update(cx, |this, cx| {
16953                    let buffer = this.buffer.read(cx).snapshot(cx);
16954                    let mut buffer_highlights = this
16955                        .document_highlights_for_position(selection.head(), &buffer)
16956                        .filter(|highlight| {
16957                            highlight.start.excerpt_id == selection.head().excerpt_id
16958                                && highlight.end.excerpt_id == selection.head().excerpt_id
16959                        });
16960                    buffer_highlights
16961                        .next()
16962                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16963                })?
16964            };
16965            if let Some(rename_range) = rename_range {
16966                this.update_in(cx, |this, window, cx| {
16967                    let snapshot = cursor_buffer.read(cx).snapshot();
16968                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16969                    let cursor_offset_in_rename_range =
16970                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16971                    let cursor_offset_in_rename_range_end =
16972                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16973
16974                    this.take_rename(false, window, cx);
16975                    let buffer = this.buffer.read(cx).read(cx);
16976                    let cursor_offset = selection.head().to_offset(&buffer);
16977                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16978                    let rename_end = rename_start + rename_buffer_range.len();
16979                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16980                    let mut old_highlight_id = None;
16981                    let old_name: Arc<str> = buffer
16982                        .chunks(rename_start..rename_end, true)
16983                        .map(|chunk| {
16984                            if old_highlight_id.is_none() {
16985                                old_highlight_id = chunk.syntax_highlight_id;
16986                            }
16987                            chunk.text
16988                        })
16989                        .collect::<String>()
16990                        .into();
16991
16992                    drop(buffer);
16993
16994                    // Position the selection in the rename editor so that it matches the current selection.
16995                    this.show_local_selections = false;
16996                    let rename_editor = cx.new(|cx| {
16997                        let mut editor = Editor::single_line(window, cx);
16998                        editor.buffer.update(cx, |buffer, cx| {
16999                            buffer.edit([(0..0, old_name.clone())], None, cx)
17000                        });
17001                        let rename_selection_range = match cursor_offset_in_rename_range
17002                            .cmp(&cursor_offset_in_rename_range_end)
17003                        {
17004                            Ordering::Equal => {
17005                                editor.select_all(&SelectAll, window, cx);
17006                                return editor;
17007                            }
17008                            Ordering::Less => {
17009                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17010                            }
17011                            Ordering::Greater => {
17012                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17013                            }
17014                        };
17015                        if rename_selection_range.end > old_name.len() {
17016                            editor.select_all(&SelectAll, window, cx);
17017                        } else {
17018                            editor.change_selections(Default::default(), window, cx, |s| {
17019                                s.select_ranges([rename_selection_range]);
17020                            });
17021                        }
17022                        editor
17023                    });
17024                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17025                        if e == &EditorEvent::Focused {
17026                            cx.emit(EditorEvent::FocusedIn)
17027                        }
17028                    })
17029                    .detach();
17030
17031                    let write_highlights =
17032                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17033                    let read_highlights =
17034                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17035                    let ranges = write_highlights
17036                        .iter()
17037                        .flat_map(|(_, ranges)| ranges.iter())
17038                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17039                        .cloned()
17040                        .collect();
17041
17042                    this.highlight_text::<Rename>(
17043                        ranges,
17044                        HighlightStyle {
17045                            fade_out: Some(0.6),
17046                            ..Default::default()
17047                        },
17048                        cx,
17049                    );
17050                    let rename_focus_handle = rename_editor.focus_handle(cx);
17051                    window.focus(&rename_focus_handle);
17052                    let block_id = this.insert_blocks(
17053                        [BlockProperties {
17054                            style: BlockStyle::Flex,
17055                            placement: BlockPlacement::Below(range.start),
17056                            height: Some(1),
17057                            render: Arc::new({
17058                                let rename_editor = rename_editor.clone();
17059                                move |cx: &mut BlockContext| {
17060                                    let mut text_style = cx.editor_style.text.clone();
17061                                    if let Some(highlight_style) = old_highlight_id
17062                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17063                                    {
17064                                        text_style = text_style.highlight(highlight_style);
17065                                    }
17066                                    div()
17067                                        .block_mouse_except_scroll()
17068                                        .pl(cx.anchor_x)
17069                                        .child(EditorElement::new(
17070                                            &rename_editor,
17071                                            EditorStyle {
17072                                                background: cx.theme().system().transparent,
17073                                                local_player: cx.editor_style.local_player,
17074                                                text: text_style,
17075                                                scrollbar_width: cx.editor_style.scrollbar_width,
17076                                                syntax: cx.editor_style.syntax.clone(),
17077                                                status: cx.editor_style.status.clone(),
17078                                                inlay_hints_style: HighlightStyle {
17079                                                    font_weight: Some(FontWeight::BOLD),
17080                                                    ..make_inlay_hints_style(cx.app)
17081                                                },
17082                                                edit_prediction_styles: make_suggestion_styles(
17083                                                    cx.app,
17084                                                ),
17085                                                ..EditorStyle::default()
17086                                            },
17087                                        ))
17088                                        .into_any_element()
17089                                }
17090                            }),
17091                            priority: 0,
17092                        }],
17093                        Some(Autoscroll::fit()),
17094                        cx,
17095                    )[0];
17096                    this.pending_rename = Some(RenameState {
17097                        range,
17098                        old_name,
17099                        editor: rename_editor,
17100                        block_id,
17101                    });
17102                })?;
17103            }
17104
17105            Ok(())
17106        }))
17107    }
17108
17109    pub fn confirm_rename(
17110        &mut self,
17111        _: &ConfirmRename,
17112        window: &mut Window,
17113        cx: &mut Context<Self>,
17114    ) -> Option<Task<Result<()>>> {
17115        let rename = self.take_rename(false, window, cx)?;
17116        let workspace = self.workspace()?.downgrade();
17117        let (buffer, start) = self
17118            .buffer
17119            .read(cx)
17120            .text_anchor_for_position(rename.range.start, cx)?;
17121        let (end_buffer, _) = self
17122            .buffer
17123            .read(cx)
17124            .text_anchor_for_position(rename.range.end, cx)?;
17125        if buffer != end_buffer {
17126            return None;
17127        }
17128
17129        let old_name = rename.old_name;
17130        let new_name = rename.editor.read(cx).text(cx);
17131
17132        let rename = self.semantics_provider.as_ref()?.perform_rename(
17133            &buffer,
17134            start,
17135            new_name.clone(),
17136            cx,
17137        )?;
17138
17139        Some(cx.spawn_in(window, async move |editor, cx| {
17140            let project_transaction = rename.await?;
17141            Self::open_project_transaction(
17142                &editor,
17143                workspace,
17144                project_transaction,
17145                format!("Rename: {}{}", old_name, new_name),
17146                cx,
17147            )
17148            .await?;
17149
17150            editor.update(cx, |editor, cx| {
17151                editor.refresh_document_highlights(cx);
17152            })?;
17153            Ok(())
17154        }))
17155    }
17156
17157    fn take_rename(
17158        &mut self,
17159        moving_cursor: bool,
17160        window: &mut Window,
17161        cx: &mut Context<Self>,
17162    ) -> Option<RenameState> {
17163        let rename = self.pending_rename.take()?;
17164        if rename.editor.focus_handle(cx).is_focused(window) {
17165            window.focus(&self.focus_handle);
17166        }
17167
17168        self.remove_blocks(
17169            [rename.block_id].into_iter().collect(),
17170            Some(Autoscroll::fit()),
17171            cx,
17172        );
17173        self.clear_highlights::<Rename>(cx);
17174        self.show_local_selections = true;
17175
17176        if moving_cursor {
17177            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17178                editor
17179                    .selections
17180                    .newest::<usize>(&editor.display_snapshot(cx))
17181                    .head()
17182            });
17183
17184            // Update the selection to match the position of the selection inside
17185            // the rename editor.
17186            let snapshot = self.buffer.read(cx).read(cx);
17187            let rename_range = rename.range.to_offset(&snapshot);
17188            let cursor_in_editor = snapshot
17189                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17190                .min(rename_range.end);
17191            drop(snapshot);
17192
17193            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17194                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17195            });
17196        } else {
17197            self.refresh_document_highlights(cx);
17198        }
17199
17200        Some(rename)
17201    }
17202
17203    pub fn pending_rename(&self) -> Option<&RenameState> {
17204        self.pending_rename.as_ref()
17205    }
17206
17207    fn format(
17208        &mut self,
17209        _: &Format,
17210        window: &mut Window,
17211        cx: &mut Context<Self>,
17212    ) -> Option<Task<Result<()>>> {
17213        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17214
17215        let project = match &self.project {
17216            Some(project) => project.clone(),
17217            None => return None,
17218        };
17219
17220        Some(self.perform_format(
17221            project,
17222            FormatTrigger::Manual,
17223            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17224            window,
17225            cx,
17226        ))
17227    }
17228
17229    fn format_selections(
17230        &mut self,
17231        _: &FormatSelections,
17232        window: &mut Window,
17233        cx: &mut Context<Self>,
17234    ) -> Option<Task<Result<()>>> {
17235        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17236
17237        let project = match &self.project {
17238            Some(project) => project.clone(),
17239            None => return None,
17240        };
17241
17242        let ranges = self
17243            .selections
17244            .all_adjusted(&self.display_snapshot(cx))
17245            .into_iter()
17246            .map(|selection| selection.range())
17247            .collect_vec();
17248
17249        Some(self.perform_format(
17250            project,
17251            FormatTrigger::Manual,
17252            FormatTarget::Ranges(ranges),
17253            window,
17254            cx,
17255        ))
17256    }
17257
17258    fn perform_format(
17259        &mut self,
17260        project: Entity<Project>,
17261        trigger: FormatTrigger,
17262        target: FormatTarget,
17263        window: &mut Window,
17264        cx: &mut Context<Self>,
17265    ) -> Task<Result<()>> {
17266        let buffer = self.buffer.clone();
17267        let (buffers, target) = match target {
17268            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17269            FormatTarget::Ranges(selection_ranges) => {
17270                let multi_buffer = buffer.read(cx);
17271                let snapshot = multi_buffer.read(cx);
17272                let mut buffers = HashSet::default();
17273                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17274                    BTreeMap::new();
17275                for selection_range in selection_ranges {
17276                    for (buffer, buffer_range, _) in
17277                        snapshot.range_to_buffer_ranges(selection_range)
17278                    {
17279                        let buffer_id = buffer.remote_id();
17280                        let start = buffer.anchor_before(buffer_range.start);
17281                        let end = buffer.anchor_after(buffer_range.end);
17282                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17283                        buffer_id_to_ranges
17284                            .entry(buffer_id)
17285                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17286                            .or_insert_with(|| vec![start..end]);
17287                    }
17288                }
17289                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17290            }
17291        };
17292
17293        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17294        let selections_prev = transaction_id_prev
17295            .and_then(|transaction_id_prev| {
17296                // default to selections as they were after the last edit, if we have them,
17297                // instead of how they are now.
17298                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17299                // will take you back to where you made the last edit, instead of staying where you scrolled
17300                self.selection_history
17301                    .transaction(transaction_id_prev)
17302                    .map(|t| t.0.clone())
17303            })
17304            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17305
17306        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17307        let format = project.update(cx, |project, cx| {
17308            project.format(buffers, target, true, trigger, cx)
17309        });
17310
17311        cx.spawn_in(window, async move |editor, cx| {
17312            let transaction = futures::select_biased! {
17313                transaction = format.log_err().fuse() => transaction,
17314                () = timeout => {
17315                    log::warn!("timed out waiting for formatting");
17316                    None
17317                }
17318            };
17319
17320            buffer
17321                .update(cx, |buffer, cx| {
17322                    if let Some(transaction) = transaction
17323                        && !buffer.is_singleton()
17324                    {
17325                        buffer.push_transaction(&transaction.0, cx);
17326                    }
17327                    cx.notify();
17328                })
17329                .ok();
17330
17331            if let Some(transaction_id_now) =
17332                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17333            {
17334                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17335                if has_new_transaction {
17336                    _ = editor.update(cx, |editor, _| {
17337                        editor
17338                            .selection_history
17339                            .insert_transaction(transaction_id_now, selections_prev);
17340                    });
17341                }
17342            }
17343
17344            Ok(())
17345        })
17346    }
17347
17348    fn organize_imports(
17349        &mut self,
17350        _: &OrganizeImports,
17351        window: &mut Window,
17352        cx: &mut Context<Self>,
17353    ) -> Option<Task<Result<()>>> {
17354        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17355        let project = match &self.project {
17356            Some(project) => project.clone(),
17357            None => return None,
17358        };
17359        Some(self.perform_code_action_kind(
17360            project,
17361            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17362            window,
17363            cx,
17364        ))
17365    }
17366
17367    fn perform_code_action_kind(
17368        &mut self,
17369        project: Entity<Project>,
17370        kind: CodeActionKind,
17371        window: &mut Window,
17372        cx: &mut Context<Self>,
17373    ) -> Task<Result<()>> {
17374        let buffer = self.buffer.clone();
17375        let buffers = buffer.read(cx).all_buffers();
17376        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17377        let apply_action = project.update(cx, |project, cx| {
17378            project.apply_code_action_kind(buffers, kind, true, cx)
17379        });
17380        cx.spawn_in(window, async move |_, cx| {
17381            let transaction = futures::select_biased! {
17382                () = timeout => {
17383                    log::warn!("timed out waiting for executing code action");
17384                    None
17385                }
17386                transaction = apply_action.log_err().fuse() => transaction,
17387            };
17388            buffer
17389                .update(cx, |buffer, cx| {
17390                    // check if we need this
17391                    if let Some(transaction) = transaction
17392                        && !buffer.is_singleton()
17393                    {
17394                        buffer.push_transaction(&transaction.0, cx);
17395                    }
17396                    cx.notify();
17397                })
17398                .ok();
17399            Ok(())
17400        })
17401    }
17402
17403    pub fn restart_language_server(
17404        &mut self,
17405        _: &RestartLanguageServer,
17406        _: &mut Window,
17407        cx: &mut Context<Self>,
17408    ) {
17409        if let Some(project) = self.project.clone() {
17410            self.buffer.update(cx, |multi_buffer, cx| {
17411                project.update(cx, |project, cx| {
17412                    project.restart_language_servers_for_buffers(
17413                        multi_buffer.all_buffers().into_iter().collect(),
17414                        HashSet::default(),
17415                        cx,
17416                    );
17417                });
17418            })
17419        }
17420    }
17421
17422    pub fn stop_language_server(
17423        &mut self,
17424        _: &StopLanguageServer,
17425        _: &mut Window,
17426        cx: &mut Context<Self>,
17427    ) {
17428        if let Some(project) = self.project.clone() {
17429            self.buffer.update(cx, |multi_buffer, cx| {
17430                project.update(cx, |project, cx| {
17431                    project.stop_language_servers_for_buffers(
17432                        multi_buffer.all_buffers().into_iter().collect(),
17433                        HashSet::default(),
17434                        cx,
17435                    );
17436                });
17437            });
17438            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17439        }
17440    }
17441
17442    fn cancel_language_server_work(
17443        workspace: &mut Workspace,
17444        _: &actions::CancelLanguageServerWork,
17445        _: &mut Window,
17446        cx: &mut Context<Workspace>,
17447    ) {
17448        let project = workspace.project();
17449        let buffers = workspace
17450            .active_item(cx)
17451            .and_then(|item| item.act_as::<Editor>(cx))
17452            .map_or(HashSet::default(), |editor| {
17453                editor.read(cx).buffer.read(cx).all_buffers()
17454            });
17455        project.update(cx, |project, cx| {
17456            project.cancel_language_server_work_for_buffers(buffers, cx);
17457        });
17458    }
17459
17460    fn show_character_palette(
17461        &mut self,
17462        _: &ShowCharacterPalette,
17463        window: &mut Window,
17464        _: &mut Context<Self>,
17465    ) {
17466        window.show_character_palette();
17467    }
17468
17469    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17470        if !self.diagnostics_enabled() {
17471            return;
17472        }
17473
17474        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17475            let buffer = self.buffer.read(cx).snapshot(cx);
17476            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17477            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17478            let is_valid = buffer
17479                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17480                .any(|entry| {
17481                    entry.diagnostic.is_primary
17482                        && !entry.range.is_empty()
17483                        && entry.range.start == primary_range_start
17484                        && entry.diagnostic.message == active_diagnostics.active_message
17485                });
17486
17487            if !is_valid {
17488                self.dismiss_diagnostics(cx);
17489            }
17490        }
17491    }
17492
17493    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17494        match &self.active_diagnostics {
17495            ActiveDiagnostic::Group(group) => Some(group),
17496            _ => None,
17497        }
17498    }
17499
17500    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17501        if !self.diagnostics_enabled() {
17502            return;
17503        }
17504        self.dismiss_diagnostics(cx);
17505        self.active_diagnostics = ActiveDiagnostic::All;
17506    }
17507
17508    fn activate_diagnostics(
17509        &mut self,
17510        buffer_id: BufferId,
17511        diagnostic: DiagnosticEntryRef<'_, usize>,
17512        window: &mut Window,
17513        cx: &mut Context<Self>,
17514    ) {
17515        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17516            return;
17517        }
17518        self.dismiss_diagnostics(cx);
17519        let snapshot = self.snapshot(window, cx);
17520        let buffer = self.buffer.read(cx).snapshot(cx);
17521        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17522            return;
17523        };
17524
17525        let diagnostic_group = buffer
17526            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17527            .collect::<Vec<_>>();
17528
17529        let blocks =
17530            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17531
17532        let blocks = self.display_map.update(cx, |display_map, cx| {
17533            display_map.insert_blocks(blocks, cx).into_iter().collect()
17534        });
17535        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17536            active_range: buffer.anchor_before(diagnostic.range.start)
17537                ..buffer.anchor_after(diagnostic.range.end),
17538            active_message: diagnostic.diagnostic.message.clone(),
17539            group_id: diagnostic.diagnostic.group_id,
17540            blocks,
17541        });
17542        cx.notify();
17543    }
17544
17545    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17546        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17547            return;
17548        };
17549
17550        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17551        if let ActiveDiagnostic::Group(group) = prev {
17552            self.display_map.update(cx, |display_map, cx| {
17553                display_map.remove_blocks(group.blocks, cx);
17554            });
17555            cx.notify();
17556        }
17557    }
17558
17559    /// Disable inline diagnostics rendering for this editor.
17560    pub fn disable_inline_diagnostics(&mut self) {
17561        self.inline_diagnostics_enabled = false;
17562        self.inline_diagnostics_update = Task::ready(());
17563        self.inline_diagnostics.clear();
17564    }
17565
17566    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17567        self.diagnostics_enabled = false;
17568        self.dismiss_diagnostics(cx);
17569        self.inline_diagnostics_update = Task::ready(());
17570        self.inline_diagnostics.clear();
17571    }
17572
17573    pub fn disable_word_completions(&mut self) {
17574        self.word_completions_enabled = false;
17575    }
17576
17577    pub fn diagnostics_enabled(&self) -> bool {
17578        self.diagnostics_enabled && self.mode.is_full()
17579    }
17580
17581    pub fn inline_diagnostics_enabled(&self) -> bool {
17582        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17583    }
17584
17585    pub fn show_inline_diagnostics(&self) -> bool {
17586        self.show_inline_diagnostics
17587    }
17588
17589    pub fn toggle_inline_diagnostics(
17590        &mut self,
17591        _: &ToggleInlineDiagnostics,
17592        window: &mut Window,
17593        cx: &mut Context<Editor>,
17594    ) {
17595        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17596        self.refresh_inline_diagnostics(false, window, cx);
17597    }
17598
17599    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17600        self.diagnostics_max_severity = severity;
17601        self.display_map.update(cx, |display_map, _| {
17602            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17603        });
17604    }
17605
17606    pub fn toggle_diagnostics(
17607        &mut self,
17608        _: &ToggleDiagnostics,
17609        window: &mut Window,
17610        cx: &mut Context<Editor>,
17611    ) {
17612        if !self.diagnostics_enabled() {
17613            return;
17614        }
17615
17616        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17617            EditorSettings::get_global(cx)
17618                .diagnostics_max_severity
17619                .filter(|severity| severity != &DiagnosticSeverity::Off)
17620                .unwrap_or(DiagnosticSeverity::Hint)
17621        } else {
17622            DiagnosticSeverity::Off
17623        };
17624        self.set_max_diagnostics_severity(new_severity, cx);
17625        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17626            self.active_diagnostics = ActiveDiagnostic::None;
17627            self.inline_diagnostics_update = Task::ready(());
17628            self.inline_diagnostics.clear();
17629        } else {
17630            self.refresh_inline_diagnostics(false, window, cx);
17631        }
17632
17633        cx.notify();
17634    }
17635
17636    pub fn toggle_minimap(
17637        &mut self,
17638        _: &ToggleMinimap,
17639        window: &mut Window,
17640        cx: &mut Context<Editor>,
17641    ) {
17642        if self.supports_minimap(cx) {
17643            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17644        }
17645    }
17646
17647    fn refresh_inline_diagnostics(
17648        &mut self,
17649        debounce: bool,
17650        window: &mut Window,
17651        cx: &mut Context<Self>,
17652    ) {
17653        let max_severity = ProjectSettings::get_global(cx)
17654            .diagnostics
17655            .inline
17656            .max_severity
17657            .unwrap_or(self.diagnostics_max_severity);
17658
17659        if !self.inline_diagnostics_enabled()
17660            || !self.show_inline_diagnostics
17661            || max_severity == DiagnosticSeverity::Off
17662        {
17663            self.inline_diagnostics_update = Task::ready(());
17664            self.inline_diagnostics.clear();
17665            return;
17666        }
17667
17668        let debounce_ms = ProjectSettings::get_global(cx)
17669            .diagnostics
17670            .inline
17671            .update_debounce_ms;
17672        let debounce = if debounce && debounce_ms > 0 {
17673            Some(Duration::from_millis(debounce_ms))
17674        } else {
17675            None
17676        };
17677        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17678            if let Some(debounce) = debounce {
17679                cx.background_executor().timer(debounce).await;
17680            }
17681            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17682                editor
17683                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17684                    .ok()
17685            }) else {
17686                return;
17687            };
17688
17689            let new_inline_diagnostics = cx
17690                .background_spawn(async move {
17691                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17692                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17693                        let message = diagnostic_entry
17694                            .diagnostic
17695                            .message
17696                            .split_once('\n')
17697                            .map(|(line, _)| line)
17698                            .map(SharedString::new)
17699                            .unwrap_or_else(|| {
17700                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17701                            });
17702                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17703                        let (Ok(i) | Err(i)) = inline_diagnostics
17704                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17705                        inline_diagnostics.insert(
17706                            i,
17707                            (
17708                                start_anchor,
17709                                InlineDiagnostic {
17710                                    message,
17711                                    group_id: diagnostic_entry.diagnostic.group_id,
17712                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17713                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17714                                    severity: diagnostic_entry.diagnostic.severity,
17715                                },
17716                            ),
17717                        );
17718                    }
17719                    inline_diagnostics
17720                })
17721                .await;
17722
17723            editor
17724                .update(cx, |editor, cx| {
17725                    editor.inline_diagnostics = new_inline_diagnostics;
17726                    cx.notify();
17727                })
17728                .ok();
17729        });
17730    }
17731
17732    fn pull_diagnostics(
17733        &mut self,
17734        buffer_id: Option<BufferId>,
17735        window: &Window,
17736        cx: &mut Context<Self>,
17737    ) -> Option<()> {
17738        if self.ignore_lsp_data() {
17739            return None;
17740        }
17741        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17742            .diagnostics
17743            .lsp_pull_diagnostics;
17744        if !pull_diagnostics_settings.enabled {
17745            return None;
17746        }
17747        let project = self.project()?.downgrade();
17748        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17749        let mut buffers = self.buffer.read(cx).all_buffers();
17750        buffers.retain(|buffer| {
17751            let buffer_id_to_retain = buffer.read(cx).remote_id();
17752            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17753                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17754        });
17755        if buffers.is_empty() {
17756            self.pull_diagnostics_task = Task::ready(());
17757            return None;
17758        }
17759
17760        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17761            cx.background_executor().timer(debounce).await;
17762
17763            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17764                buffers
17765                    .into_iter()
17766                    .filter_map(|buffer| {
17767                        project
17768                            .update(cx, |project, cx| {
17769                                project.lsp_store().update(cx, |lsp_store, cx| {
17770                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17771                                })
17772                            })
17773                            .ok()
17774                    })
17775                    .collect::<FuturesUnordered<_>>()
17776            }) else {
17777                return;
17778            };
17779
17780            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17781                match pull_task {
17782                    Ok(()) => {
17783                        if editor
17784                            .update_in(cx, |editor, window, cx| {
17785                                editor.update_diagnostics_state(window, cx);
17786                            })
17787                            .is_err()
17788                        {
17789                            return;
17790                        }
17791                    }
17792                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17793                }
17794            }
17795        });
17796
17797        Some(())
17798    }
17799
17800    pub fn set_selections_from_remote(
17801        &mut self,
17802        selections: Vec<Selection<Anchor>>,
17803        pending_selection: Option<Selection<Anchor>>,
17804        window: &mut Window,
17805        cx: &mut Context<Self>,
17806    ) {
17807        let old_cursor_position = self.selections.newest_anchor().head();
17808        self.selections.change_with(cx, |s| {
17809            s.select_anchors(selections);
17810            if let Some(pending_selection) = pending_selection {
17811                s.set_pending(pending_selection, SelectMode::Character);
17812            } else {
17813                s.clear_pending();
17814            }
17815        });
17816        self.selections_did_change(
17817            false,
17818            &old_cursor_position,
17819            SelectionEffects::default(),
17820            window,
17821            cx,
17822        );
17823    }
17824
17825    pub fn transact(
17826        &mut self,
17827        window: &mut Window,
17828        cx: &mut Context<Self>,
17829        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17830    ) -> Option<TransactionId> {
17831        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17832            this.start_transaction_at(Instant::now(), window, cx);
17833            update(this, window, cx);
17834            this.end_transaction_at(Instant::now(), cx)
17835        })
17836    }
17837
17838    pub fn start_transaction_at(
17839        &mut self,
17840        now: Instant,
17841        window: &mut Window,
17842        cx: &mut Context<Self>,
17843    ) -> Option<TransactionId> {
17844        self.end_selection(window, cx);
17845        if let Some(tx_id) = self
17846            .buffer
17847            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17848        {
17849            self.selection_history
17850                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17851            cx.emit(EditorEvent::TransactionBegun {
17852                transaction_id: tx_id,
17853            });
17854            Some(tx_id)
17855        } else {
17856            None
17857        }
17858    }
17859
17860    pub fn end_transaction_at(
17861        &mut self,
17862        now: Instant,
17863        cx: &mut Context<Self>,
17864    ) -> Option<TransactionId> {
17865        if let Some(transaction_id) = self
17866            .buffer
17867            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17868        {
17869            if let Some((_, end_selections)) =
17870                self.selection_history.transaction_mut(transaction_id)
17871            {
17872                *end_selections = Some(self.selections.disjoint_anchors_arc());
17873            } else {
17874                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17875            }
17876
17877            cx.emit(EditorEvent::Edited { transaction_id });
17878            Some(transaction_id)
17879        } else {
17880            None
17881        }
17882    }
17883
17884    pub fn modify_transaction_selection_history(
17885        &mut self,
17886        transaction_id: TransactionId,
17887        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17888    ) -> bool {
17889        self.selection_history
17890            .transaction_mut(transaction_id)
17891            .map(modify)
17892            .is_some()
17893    }
17894
17895    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17896        if self.selection_mark_mode {
17897            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17898                s.move_with(|_, sel| {
17899                    sel.collapse_to(sel.head(), SelectionGoal::None);
17900                });
17901            })
17902        }
17903        self.selection_mark_mode = true;
17904        cx.notify();
17905    }
17906
17907    pub fn swap_selection_ends(
17908        &mut self,
17909        _: &actions::SwapSelectionEnds,
17910        window: &mut Window,
17911        cx: &mut Context<Self>,
17912    ) {
17913        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17914            s.move_with(|_, sel| {
17915                if sel.start != sel.end {
17916                    sel.reversed = !sel.reversed
17917                }
17918            });
17919        });
17920        self.request_autoscroll(Autoscroll::newest(), cx);
17921        cx.notify();
17922    }
17923
17924    pub fn toggle_focus(
17925        workspace: &mut Workspace,
17926        _: &actions::ToggleFocus,
17927        window: &mut Window,
17928        cx: &mut Context<Workspace>,
17929    ) {
17930        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17931            return;
17932        };
17933        workspace.activate_item(&item, true, true, window, cx);
17934    }
17935
17936    pub fn toggle_fold(
17937        &mut self,
17938        _: &actions::ToggleFold,
17939        window: &mut Window,
17940        cx: &mut Context<Self>,
17941    ) {
17942        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
17943            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17944            let selection = self.selections.newest::<Point>(&display_map);
17945
17946            let range = if selection.is_empty() {
17947                let point = selection.head().to_display_point(&display_map);
17948                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17949                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17950                    .to_point(&display_map);
17951                start..end
17952            } else {
17953                selection.range()
17954            };
17955            if display_map.folds_in_range(range).next().is_some() {
17956                self.unfold_lines(&Default::default(), window, cx)
17957            } else {
17958                self.fold(&Default::default(), window, cx)
17959            }
17960        } else {
17961            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17962            let buffer_ids: HashSet<_> = self
17963                .selections
17964                .disjoint_anchor_ranges()
17965                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17966                .collect();
17967
17968            let should_unfold = buffer_ids
17969                .iter()
17970                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17971
17972            for buffer_id in buffer_ids {
17973                if should_unfold {
17974                    self.unfold_buffer(buffer_id, cx);
17975                } else {
17976                    self.fold_buffer(buffer_id, cx);
17977                }
17978            }
17979        }
17980    }
17981
17982    pub fn toggle_fold_recursive(
17983        &mut self,
17984        _: &actions::ToggleFoldRecursive,
17985        window: &mut Window,
17986        cx: &mut Context<Self>,
17987    ) {
17988        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17989
17990        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17991        let range = if selection.is_empty() {
17992            let point = selection.head().to_display_point(&display_map);
17993            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17994            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17995                .to_point(&display_map);
17996            start..end
17997        } else {
17998            selection.range()
17999        };
18000        if display_map.folds_in_range(range).next().is_some() {
18001            self.unfold_recursive(&Default::default(), window, cx)
18002        } else {
18003            self.fold_recursive(&Default::default(), window, cx)
18004        }
18005    }
18006
18007    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18008        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18009            let mut to_fold = Vec::new();
18010            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18011            let selections = self.selections.all_adjusted(&display_map);
18012
18013            for selection in selections {
18014                let range = selection.range().sorted();
18015                let buffer_start_row = range.start.row;
18016
18017                if range.start.row != range.end.row {
18018                    let mut found = false;
18019                    let mut row = range.start.row;
18020                    while row <= range.end.row {
18021                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18022                        {
18023                            found = true;
18024                            row = crease.range().end.row + 1;
18025                            to_fold.push(crease);
18026                        } else {
18027                            row += 1
18028                        }
18029                    }
18030                    if found {
18031                        continue;
18032                    }
18033                }
18034
18035                for row in (0..=range.start.row).rev() {
18036                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18037                        && crease.range().end.row >= buffer_start_row
18038                    {
18039                        to_fold.push(crease);
18040                        if row <= range.start.row {
18041                            break;
18042                        }
18043                    }
18044                }
18045            }
18046
18047            self.fold_creases(to_fold, true, window, cx);
18048        } else {
18049            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18050            let buffer_ids = self
18051                .selections
18052                .disjoint_anchor_ranges()
18053                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18054                .collect::<HashSet<_>>();
18055            for buffer_id in buffer_ids {
18056                self.fold_buffer(buffer_id, cx);
18057            }
18058        }
18059    }
18060
18061    pub fn toggle_fold_all(
18062        &mut self,
18063        _: &actions::ToggleFoldAll,
18064        window: &mut Window,
18065        cx: &mut Context<Self>,
18066    ) {
18067        if self.buffer.read(cx).is_singleton() {
18068            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18069            let has_folds = display_map
18070                .folds_in_range(0..display_map.buffer_snapshot().len())
18071                .next()
18072                .is_some();
18073
18074            if has_folds {
18075                self.unfold_all(&actions::UnfoldAll, window, cx);
18076            } else {
18077                self.fold_all(&actions::FoldAll, window, cx);
18078            }
18079        } else {
18080            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18081            let should_unfold = buffer_ids
18082                .iter()
18083                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18084
18085            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18086                editor
18087                    .update_in(cx, |editor, _, cx| {
18088                        for buffer_id in buffer_ids {
18089                            if should_unfold {
18090                                editor.unfold_buffer(buffer_id, cx);
18091                            } else {
18092                                editor.fold_buffer(buffer_id, cx);
18093                            }
18094                        }
18095                    })
18096                    .ok();
18097            });
18098        }
18099    }
18100
18101    fn fold_at_level(
18102        &mut self,
18103        fold_at: &FoldAtLevel,
18104        window: &mut Window,
18105        cx: &mut Context<Self>,
18106    ) {
18107        if !self.buffer.read(cx).is_singleton() {
18108            return;
18109        }
18110
18111        let fold_at_level = fold_at.0;
18112        let snapshot = self.buffer.read(cx).snapshot(cx);
18113        let mut to_fold = Vec::new();
18114        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18115
18116        let row_ranges_to_keep: Vec<Range<u32>> = self
18117            .selections
18118            .all::<Point>(&self.display_snapshot(cx))
18119            .into_iter()
18120            .map(|sel| sel.start.row..sel.end.row)
18121            .collect();
18122
18123        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18124            while start_row < end_row {
18125                match self
18126                    .snapshot(window, cx)
18127                    .crease_for_buffer_row(MultiBufferRow(start_row))
18128                {
18129                    Some(crease) => {
18130                        let nested_start_row = crease.range().start.row + 1;
18131                        let nested_end_row = crease.range().end.row;
18132
18133                        if current_level < fold_at_level {
18134                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18135                        } else if current_level == fold_at_level {
18136                            // Fold iff there is no selection completely contained within the fold region
18137                            if !row_ranges_to_keep.iter().any(|selection| {
18138                                selection.end >= nested_start_row
18139                                    && selection.start <= nested_end_row
18140                            }) {
18141                                to_fold.push(crease);
18142                            }
18143                        }
18144
18145                        start_row = nested_end_row + 1;
18146                    }
18147                    None => start_row += 1,
18148                }
18149            }
18150        }
18151
18152        self.fold_creases(to_fold, true, window, cx);
18153    }
18154
18155    pub fn fold_at_level_1(
18156        &mut self,
18157        _: &actions::FoldAtLevel1,
18158        window: &mut Window,
18159        cx: &mut Context<Self>,
18160    ) {
18161        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18162    }
18163
18164    pub fn fold_at_level_2(
18165        &mut self,
18166        _: &actions::FoldAtLevel2,
18167        window: &mut Window,
18168        cx: &mut Context<Self>,
18169    ) {
18170        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18171    }
18172
18173    pub fn fold_at_level_3(
18174        &mut self,
18175        _: &actions::FoldAtLevel3,
18176        window: &mut Window,
18177        cx: &mut Context<Self>,
18178    ) {
18179        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18180    }
18181
18182    pub fn fold_at_level_4(
18183        &mut self,
18184        _: &actions::FoldAtLevel4,
18185        window: &mut Window,
18186        cx: &mut Context<Self>,
18187    ) {
18188        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18189    }
18190
18191    pub fn fold_at_level_5(
18192        &mut self,
18193        _: &actions::FoldAtLevel5,
18194        window: &mut Window,
18195        cx: &mut Context<Self>,
18196    ) {
18197        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18198    }
18199
18200    pub fn fold_at_level_6(
18201        &mut self,
18202        _: &actions::FoldAtLevel6,
18203        window: &mut Window,
18204        cx: &mut Context<Self>,
18205    ) {
18206        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18207    }
18208
18209    pub fn fold_at_level_7(
18210        &mut self,
18211        _: &actions::FoldAtLevel7,
18212        window: &mut Window,
18213        cx: &mut Context<Self>,
18214    ) {
18215        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18216    }
18217
18218    pub fn fold_at_level_8(
18219        &mut self,
18220        _: &actions::FoldAtLevel8,
18221        window: &mut Window,
18222        cx: &mut Context<Self>,
18223    ) {
18224        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18225    }
18226
18227    pub fn fold_at_level_9(
18228        &mut self,
18229        _: &actions::FoldAtLevel9,
18230        window: &mut Window,
18231        cx: &mut Context<Self>,
18232    ) {
18233        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18234    }
18235
18236    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18237        if self.buffer.read(cx).is_singleton() {
18238            let mut fold_ranges = Vec::new();
18239            let snapshot = self.buffer.read(cx).snapshot(cx);
18240
18241            for row in 0..snapshot.max_row().0 {
18242                if let Some(foldable_range) = self
18243                    .snapshot(window, cx)
18244                    .crease_for_buffer_row(MultiBufferRow(row))
18245                {
18246                    fold_ranges.push(foldable_range);
18247                }
18248            }
18249
18250            self.fold_creases(fold_ranges, true, window, cx);
18251        } else {
18252            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18253                editor
18254                    .update_in(cx, |editor, _, cx| {
18255                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18256                            editor.fold_buffer(buffer_id, cx);
18257                        }
18258                    })
18259                    .ok();
18260            });
18261        }
18262    }
18263
18264    pub fn fold_function_bodies(
18265        &mut self,
18266        _: &actions::FoldFunctionBodies,
18267        window: &mut Window,
18268        cx: &mut Context<Self>,
18269    ) {
18270        let snapshot = self.buffer.read(cx).snapshot(cx);
18271
18272        let ranges = snapshot
18273            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18274            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18275            .collect::<Vec<_>>();
18276
18277        let creases = ranges
18278            .into_iter()
18279            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18280            .collect();
18281
18282        self.fold_creases(creases, true, window, cx);
18283    }
18284
18285    pub fn fold_recursive(
18286        &mut self,
18287        _: &actions::FoldRecursive,
18288        window: &mut Window,
18289        cx: &mut Context<Self>,
18290    ) {
18291        let mut to_fold = Vec::new();
18292        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18293        let selections = self.selections.all_adjusted(&display_map);
18294
18295        for selection in selections {
18296            let range = selection.range().sorted();
18297            let buffer_start_row = range.start.row;
18298
18299            if range.start.row != range.end.row {
18300                let mut found = false;
18301                for row in range.start.row..=range.end.row {
18302                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18303                        found = true;
18304                        to_fold.push(crease);
18305                    }
18306                }
18307                if found {
18308                    continue;
18309                }
18310            }
18311
18312            for row in (0..=range.start.row).rev() {
18313                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18314                    if crease.range().end.row >= buffer_start_row {
18315                        to_fold.push(crease);
18316                    } else {
18317                        break;
18318                    }
18319                }
18320            }
18321        }
18322
18323        self.fold_creases(to_fold, true, window, cx);
18324    }
18325
18326    pub fn fold_at(
18327        &mut self,
18328        buffer_row: MultiBufferRow,
18329        window: &mut Window,
18330        cx: &mut Context<Self>,
18331    ) {
18332        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18333
18334        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18335            let autoscroll = self
18336                .selections
18337                .all::<Point>(&display_map)
18338                .iter()
18339                .any(|selection| crease.range().overlaps(&selection.range()));
18340
18341            self.fold_creases(vec![crease], autoscroll, window, cx);
18342        }
18343    }
18344
18345    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18346        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18347            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18348            let buffer = display_map.buffer_snapshot();
18349            let selections = self.selections.all::<Point>(&display_map);
18350            let ranges = selections
18351                .iter()
18352                .map(|s| {
18353                    let range = s.display_range(&display_map).sorted();
18354                    let mut start = range.start.to_point(&display_map);
18355                    let mut end = range.end.to_point(&display_map);
18356                    start.column = 0;
18357                    end.column = buffer.line_len(MultiBufferRow(end.row));
18358                    start..end
18359                })
18360                .collect::<Vec<_>>();
18361
18362            self.unfold_ranges(&ranges, true, true, cx);
18363        } else {
18364            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18365            let buffer_ids = self
18366                .selections
18367                .disjoint_anchor_ranges()
18368                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18369                .collect::<HashSet<_>>();
18370            for buffer_id in buffer_ids {
18371                self.unfold_buffer(buffer_id, cx);
18372            }
18373        }
18374    }
18375
18376    pub fn unfold_recursive(
18377        &mut self,
18378        _: &UnfoldRecursive,
18379        _window: &mut Window,
18380        cx: &mut Context<Self>,
18381    ) {
18382        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18383        let selections = self.selections.all::<Point>(&display_map);
18384        let ranges = selections
18385            .iter()
18386            .map(|s| {
18387                let mut range = s.display_range(&display_map).sorted();
18388                *range.start.column_mut() = 0;
18389                *range.end.column_mut() = display_map.line_len(range.end.row());
18390                let start = range.start.to_point(&display_map);
18391                let end = range.end.to_point(&display_map);
18392                start..end
18393            })
18394            .collect::<Vec<_>>();
18395
18396        self.unfold_ranges(&ranges, true, true, cx);
18397    }
18398
18399    pub fn unfold_at(
18400        &mut self,
18401        buffer_row: MultiBufferRow,
18402        _window: &mut Window,
18403        cx: &mut Context<Self>,
18404    ) {
18405        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18406
18407        let intersection_range = Point::new(buffer_row.0, 0)
18408            ..Point::new(
18409                buffer_row.0,
18410                display_map.buffer_snapshot().line_len(buffer_row),
18411            );
18412
18413        let autoscroll = self
18414            .selections
18415            .all::<Point>(&display_map)
18416            .iter()
18417            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18418
18419        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18420    }
18421
18422    pub fn unfold_all(
18423        &mut self,
18424        _: &actions::UnfoldAll,
18425        _window: &mut Window,
18426        cx: &mut Context<Self>,
18427    ) {
18428        if self.buffer.read(cx).is_singleton() {
18429            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18430            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18431        } else {
18432            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18433                editor
18434                    .update(cx, |editor, cx| {
18435                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18436                            editor.unfold_buffer(buffer_id, cx);
18437                        }
18438                    })
18439                    .ok();
18440            });
18441        }
18442    }
18443
18444    pub fn fold_selected_ranges(
18445        &mut self,
18446        _: &FoldSelectedRanges,
18447        window: &mut Window,
18448        cx: &mut Context<Self>,
18449    ) {
18450        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18451        let selections = self.selections.all_adjusted(&display_map);
18452        let ranges = selections
18453            .into_iter()
18454            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18455            .collect::<Vec<_>>();
18456        self.fold_creases(ranges, true, window, cx);
18457    }
18458
18459    pub fn fold_ranges<T: ToOffset + Clone>(
18460        &mut self,
18461        ranges: Vec<Range<T>>,
18462        auto_scroll: bool,
18463        window: &mut Window,
18464        cx: &mut Context<Self>,
18465    ) {
18466        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18467        let ranges = ranges
18468            .into_iter()
18469            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18470            .collect::<Vec<_>>();
18471        self.fold_creases(ranges, auto_scroll, window, cx);
18472    }
18473
18474    pub fn fold_creases<T: ToOffset + Clone>(
18475        &mut self,
18476        creases: Vec<Crease<T>>,
18477        auto_scroll: bool,
18478        _window: &mut Window,
18479        cx: &mut Context<Self>,
18480    ) {
18481        if creases.is_empty() {
18482            return;
18483        }
18484
18485        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18486
18487        if auto_scroll {
18488            self.request_autoscroll(Autoscroll::fit(), cx);
18489        }
18490
18491        cx.notify();
18492
18493        self.scrollbar_marker_state.dirty = true;
18494        self.folds_did_change(cx);
18495    }
18496
18497    /// Removes any folds whose ranges intersect any of the given ranges.
18498    pub fn unfold_ranges<T: ToOffset + Clone>(
18499        &mut self,
18500        ranges: &[Range<T>],
18501        inclusive: bool,
18502        auto_scroll: bool,
18503        cx: &mut Context<Self>,
18504    ) {
18505        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18506            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18507        });
18508        self.folds_did_change(cx);
18509    }
18510
18511    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18512        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18513            return;
18514        }
18515        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18516        self.display_map.update(cx, |display_map, cx| {
18517            display_map.fold_buffers([buffer_id], cx)
18518        });
18519        cx.emit(EditorEvent::BufferFoldToggled {
18520            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18521            folded: true,
18522        });
18523        cx.notify();
18524    }
18525
18526    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18527        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18528            return;
18529        }
18530        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18531        self.display_map.update(cx, |display_map, cx| {
18532            display_map.unfold_buffers([buffer_id], cx);
18533        });
18534        cx.emit(EditorEvent::BufferFoldToggled {
18535            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18536            folded: false,
18537        });
18538        cx.notify();
18539    }
18540
18541    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18542        self.display_map.read(cx).is_buffer_folded(buffer)
18543    }
18544
18545    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18546        self.display_map.read(cx).folded_buffers()
18547    }
18548
18549    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18550        self.display_map.update(cx, |display_map, cx| {
18551            display_map.disable_header_for_buffer(buffer_id, cx);
18552        });
18553        cx.notify();
18554    }
18555
18556    /// Removes any folds with the given ranges.
18557    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18558        &mut self,
18559        ranges: &[Range<T>],
18560        type_id: TypeId,
18561        auto_scroll: bool,
18562        cx: &mut Context<Self>,
18563    ) {
18564        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18565            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18566        });
18567        self.folds_did_change(cx);
18568    }
18569
18570    fn remove_folds_with<T: ToOffset + Clone>(
18571        &mut self,
18572        ranges: &[Range<T>],
18573        auto_scroll: bool,
18574        cx: &mut Context<Self>,
18575        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18576    ) {
18577        if ranges.is_empty() {
18578            return;
18579        }
18580
18581        let mut buffers_affected = HashSet::default();
18582        let multi_buffer = self.buffer().read(cx);
18583        for range in ranges {
18584            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18585                buffers_affected.insert(buffer.read(cx).remote_id());
18586            };
18587        }
18588
18589        self.display_map.update(cx, update);
18590
18591        if auto_scroll {
18592            self.request_autoscroll(Autoscroll::fit(), cx);
18593        }
18594
18595        cx.notify();
18596        self.scrollbar_marker_state.dirty = true;
18597        self.active_indent_guides_state.dirty = true;
18598    }
18599
18600    pub fn update_renderer_widths(
18601        &mut self,
18602        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18603        cx: &mut Context<Self>,
18604    ) -> bool {
18605        self.display_map
18606            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18607    }
18608
18609    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18610        self.display_map.read(cx).fold_placeholder.clone()
18611    }
18612
18613    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18614        self.buffer.update(cx, |buffer, cx| {
18615            buffer.set_all_diff_hunks_expanded(cx);
18616        });
18617    }
18618
18619    pub fn expand_all_diff_hunks(
18620        &mut self,
18621        _: &ExpandAllDiffHunks,
18622        _window: &mut Window,
18623        cx: &mut Context<Self>,
18624    ) {
18625        self.buffer.update(cx, |buffer, cx| {
18626            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18627        });
18628    }
18629
18630    pub fn collapse_all_diff_hunks(
18631        &mut self,
18632        _: &CollapseAllDiffHunks,
18633        _window: &mut Window,
18634        cx: &mut Context<Self>,
18635    ) {
18636        self.buffer.update(cx, |buffer, cx| {
18637            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18638        });
18639    }
18640
18641    pub fn toggle_selected_diff_hunks(
18642        &mut self,
18643        _: &ToggleSelectedDiffHunks,
18644        _window: &mut Window,
18645        cx: &mut Context<Self>,
18646    ) {
18647        let ranges: Vec<_> = self
18648            .selections
18649            .disjoint_anchors()
18650            .iter()
18651            .map(|s| s.range())
18652            .collect();
18653        self.toggle_diff_hunks_in_ranges(ranges, cx);
18654    }
18655
18656    pub fn diff_hunks_in_ranges<'a>(
18657        &'a self,
18658        ranges: &'a [Range<Anchor>],
18659        buffer: &'a MultiBufferSnapshot,
18660    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18661        ranges.iter().flat_map(move |range| {
18662            let end_excerpt_id = range.end.excerpt_id;
18663            let range = range.to_point(buffer);
18664            let mut peek_end = range.end;
18665            if range.end.row < buffer.max_row().0 {
18666                peek_end = Point::new(range.end.row + 1, 0);
18667            }
18668            buffer
18669                .diff_hunks_in_range(range.start..peek_end)
18670                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18671        })
18672    }
18673
18674    pub fn has_stageable_diff_hunks_in_ranges(
18675        &self,
18676        ranges: &[Range<Anchor>],
18677        snapshot: &MultiBufferSnapshot,
18678    ) -> bool {
18679        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18680        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18681    }
18682
18683    pub fn toggle_staged_selected_diff_hunks(
18684        &mut self,
18685        _: &::git::ToggleStaged,
18686        _: &mut Window,
18687        cx: &mut Context<Self>,
18688    ) {
18689        let snapshot = self.buffer.read(cx).snapshot(cx);
18690        let ranges: Vec<_> = self
18691            .selections
18692            .disjoint_anchors()
18693            .iter()
18694            .map(|s| s.range())
18695            .collect();
18696        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18697        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18698    }
18699
18700    pub fn set_render_diff_hunk_controls(
18701        &mut self,
18702        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18703        cx: &mut Context<Self>,
18704    ) {
18705        self.render_diff_hunk_controls = render_diff_hunk_controls;
18706        cx.notify();
18707    }
18708
18709    pub fn stage_and_next(
18710        &mut self,
18711        _: &::git::StageAndNext,
18712        window: &mut Window,
18713        cx: &mut Context<Self>,
18714    ) {
18715        self.do_stage_or_unstage_and_next(true, window, cx);
18716    }
18717
18718    pub fn unstage_and_next(
18719        &mut self,
18720        _: &::git::UnstageAndNext,
18721        window: &mut Window,
18722        cx: &mut Context<Self>,
18723    ) {
18724        self.do_stage_or_unstage_and_next(false, window, cx);
18725    }
18726
18727    pub fn stage_or_unstage_diff_hunks(
18728        &mut self,
18729        stage: bool,
18730        ranges: Vec<Range<Anchor>>,
18731        cx: &mut Context<Self>,
18732    ) {
18733        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18734        cx.spawn(async move |this, cx| {
18735            task.await?;
18736            this.update(cx, |this, cx| {
18737                let snapshot = this.buffer.read(cx).snapshot(cx);
18738                let chunk_by = this
18739                    .diff_hunks_in_ranges(&ranges, &snapshot)
18740                    .chunk_by(|hunk| hunk.buffer_id);
18741                for (buffer_id, hunks) in &chunk_by {
18742                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18743                }
18744            })
18745        })
18746        .detach_and_log_err(cx);
18747    }
18748
18749    fn save_buffers_for_ranges_if_needed(
18750        &mut self,
18751        ranges: &[Range<Anchor>],
18752        cx: &mut Context<Editor>,
18753    ) -> Task<Result<()>> {
18754        let multibuffer = self.buffer.read(cx);
18755        let snapshot = multibuffer.read(cx);
18756        let buffer_ids: HashSet<_> = ranges
18757            .iter()
18758            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18759            .collect();
18760        drop(snapshot);
18761
18762        let mut buffers = HashSet::default();
18763        for buffer_id in buffer_ids {
18764            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18765                let buffer = buffer_entity.read(cx);
18766                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18767                {
18768                    buffers.insert(buffer_entity);
18769                }
18770            }
18771        }
18772
18773        if let Some(project) = &self.project {
18774            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18775        } else {
18776            Task::ready(Ok(()))
18777        }
18778    }
18779
18780    fn do_stage_or_unstage_and_next(
18781        &mut self,
18782        stage: bool,
18783        window: &mut Window,
18784        cx: &mut Context<Self>,
18785    ) {
18786        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18787
18788        if ranges.iter().any(|range| range.start != range.end) {
18789            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18790            return;
18791        }
18792
18793        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18794        let snapshot = self.snapshot(window, cx);
18795        let position = self
18796            .selections
18797            .newest::<Point>(&snapshot.display_snapshot)
18798            .head();
18799        let mut row = snapshot
18800            .buffer_snapshot()
18801            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18802            .find(|hunk| hunk.row_range.start.0 > position.row)
18803            .map(|hunk| hunk.row_range.start);
18804
18805        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18806        // Outside of the project diff editor, wrap around to the beginning.
18807        if !all_diff_hunks_expanded {
18808            row = row.or_else(|| {
18809                snapshot
18810                    .buffer_snapshot()
18811                    .diff_hunks_in_range(Point::zero()..position)
18812                    .find(|hunk| hunk.row_range.end.0 < position.row)
18813                    .map(|hunk| hunk.row_range.start)
18814            });
18815        }
18816
18817        if let Some(row) = row {
18818            let destination = Point::new(row.0, 0);
18819            let autoscroll = Autoscroll::center();
18820
18821            self.unfold_ranges(&[destination..destination], false, false, cx);
18822            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18823                s.select_ranges([destination..destination]);
18824            });
18825        }
18826    }
18827
18828    fn do_stage_or_unstage(
18829        &self,
18830        stage: bool,
18831        buffer_id: BufferId,
18832        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18833        cx: &mut App,
18834    ) -> Option<()> {
18835        let project = self.project()?;
18836        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18837        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18838        let buffer_snapshot = buffer.read(cx).snapshot();
18839        let file_exists = buffer_snapshot
18840            .file()
18841            .is_some_and(|file| file.disk_state().exists());
18842        diff.update(cx, |diff, cx| {
18843            diff.stage_or_unstage_hunks(
18844                stage,
18845                &hunks
18846                    .map(|hunk| buffer_diff::DiffHunk {
18847                        buffer_range: hunk.buffer_range,
18848                        diff_base_byte_range: hunk.diff_base_byte_range,
18849                        secondary_status: hunk.secondary_status,
18850                        range: Point::zero()..Point::zero(), // unused
18851                    })
18852                    .collect::<Vec<_>>(),
18853                &buffer_snapshot,
18854                file_exists,
18855                cx,
18856            )
18857        });
18858        None
18859    }
18860
18861    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18862        let ranges: Vec<_> = self
18863            .selections
18864            .disjoint_anchors()
18865            .iter()
18866            .map(|s| s.range())
18867            .collect();
18868        self.buffer
18869            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18870    }
18871
18872    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18873        self.buffer.update(cx, |buffer, cx| {
18874            let ranges = vec![Anchor::min()..Anchor::max()];
18875            if !buffer.all_diff_hunks_expanded()
18876                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18877            {
18878                buffer.collapse_diff_hunks(ranges, cx);
18879                true
18880            } else {
18881                false
18882            }
18883        })
18884    }
18885
18886    fn toggle_diff_hunks_in_ranges(
18887        &mut self,
18888        ranges: Vec<Range<Anchor>>,
18889        cx: &mut Context<Editor>,
18890    ) {
18891        self.buffer.update(cx, |buffer, cx| {
18892            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18893            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18894        })
18895    }
18896
18897    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18898        self.buffer.update(cx, |buffer, cx| {
18899            let snapshot = buffer.snapshot(cx);
18900            let excerpt_id = range.end.excerpt_id;
18901            let point_range = range.to_point(&snapshot);
18902            let expand = !buffer.single_hunk_is_expanded(range, cx);
18903            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18904        })
18905    }
18906
18907    pub(crate) fn apply_all_diff_hunks(
18908        &mut self,
18909        _: &ApplyAllDiffHunks,
18910        window: &mut Window,
18911        cx: &mut Context<Self>,
18912    ) {
18913        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18914
18915        let buffers = self.buffer.read(cx).all_buffers();
18916        for branch_buffer in buffers {
18917            branch_buffer.update(cx, |branch_buffer, cx| {
18918                branch_buffer.merge_into_base(Vec::new(), cx);
18919            });
18920        }
18921
18922        if let Some(project) = self.project.clone() {
18923            self.save(
18924                SaveOptions {
18925                    format: true,
18926                    autosave: false,
18927                },
18928                project,
18929                window,
18930                cx,
18931            )
18932            .detach_and_log_err(cx);
18933        }
18934    }
18935
18936    pub(crate) fn apply_selected_diff_hunks(
18937        &mut self,
18938        _: &ApplyDiffHunk,
18939        window: &mut Window,
18940        cx: &mut Context<Self>,
18941    ) {
18942        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18943        let snapshot = self.snapshot(window, cx);
18944        let hunks = snapshot.hunks_for_ranges(
18945            self.selections
18946                .all(&snapshot.display_snapshot)
18947                .into_iter()
18948                .map(|selection| selection.range()),
18949        );
18950        let mut ranges_by_buffer = HashMap::default();
18951        self.transact(window, cx, |editor, _window, cx| {
18952            for hunk in hunks {
18953                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18954                    ranges_by_buffer
18955                        .entry(buffer.clone())
18956                        .or_insert_with(Vec::new)
18957                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18958                }
18959            }
18960
18961            for (buffer, ranges) in ranges_by_buffer {
18962                buffer.update(cx, |buffer, cx| {
18963                    buffer.merge_into_base(ranges, cx);
18964                });
18965            }
18966        });
18967
18968        if let Some(project) = self.project.clone() {
18969            self.save(
18970                SaveOptions {
18971                    format: true,
18972                    autosave: false,
18973                },
18974                project,
18975                window,
18976                cx,
18977            )
18978            .detach_and_log_err(cx);
18979        }
18980    }
18981
18982    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18983        if hovered != self.gutter_hovered {
18984            self.gutter_hovered = hovered;
18985            cx.notify();
18986        }
18987    }
18988
18989    pub fn insert_blocks(
18990        &mut self,
18991        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18992        autoscroll: Option<Autoscroll>,
18993        cx: &mut Context<Self>,
18994    ) -> Vec<CustomBlockId> {
18995        let blocks = self
18996            .display_map
18997            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18998        if let Some(autoscroll) = autoscroll {
18999            self.request_autoscroll(autoscroll, cx);
19000        }
19001        cx.notify();
19002        blocks
19003    }
19004
19005    pub fn resize_blocks(
19006        &mut self,
19007        heights: HashMap<CustomBlockId, u32>,
19008        autoscroll: Option<Autoscroll>,
19009        cx: &mut Context<Self>,
19010    ) {
19011        self.display_map
19012            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19013        if let Some(autoscroll) = autoscroll {
19014            self.request_autoscroll(autoscroll, cx);
19015        }
19016        cx.notify();
19017    }
19018
19019    pub fn replace_blocks(
19020        &mut self,
19021        renderers: HashMap<CustomBlockId, RenderBlock>,
19022        autoscroll: Option<Autoscroll>,
19023        cx: &mut Context<Self>,
19024    ) {
19025        self.display_map
19026            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19027        if let Some(autoscroll) = autoscroll {
19028            self.request_autoscroll(autoscroll, cx);
19029        }
19030        cx.notify();
19031    }
19032
19033    pub fn remove_blocks(
19034        &mut self,
19035        block_ids: HashSet<CustomBlockId>,
19036        autoscroll: Option<Autoscroll>,
19037        cx: &mut Context<Self>,
19038    ) {
19039        self.display_map.update(cx, |display_map, cx| {
19040            display_map.remove_blocks(block_ids, cx)
19041        });
19042        if let Some(autoscroll) = autoscroll {
19043            self.request_autoscroll(autoscroll, cx);
19044        }
19045        cx.notify();
19046    }
19047
19048    pub fn row_for_block(
19049        &self,
19050        block_id: CustomBlockId,
19051        cx: &mut Context<Self>,
19052    ) -> Option<DisplayRow> {
19053        self.display_map
19054            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19055    }
19056
19057    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19058        self.focused_block = Some(focused_block);
19059    }
19060
19061    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19062        self.focused_block.take()
19063    }
19064
19065    pub fn insert_creases(
19066        &mut self,
19067        creases: impl IntoIterator<Item = Crease<Anchor>>,
19068        cx: &mut Context<Self>,
19069    ) -> Vec<CreaseId> {
19070        self.display_map
19071            .update(cx, |map, cx| map.insert_creases(creases, cx))
19072    }
19073
19074    pub fn remove_creases(
19075        &mut self,
19076        ids: impl IntoIterator<Item = CreaseId>,
19077        cx: &mut Context<Self>,
19078    ) -> Vec<(CreaseId, Range<Anchor>)> {
19079        self.display_map
19080            .update(cx, |map, cx| map.remove_creases(ids, cx))
19081    }
19082
19083    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19084        self.display_map
19085            .update(cx, |map, cx| map.snapshot(cx))
19086            .longest_row()
19087    }
19088
19089    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19090        self.display_map
19091            .update(cx, |map, cx| map.snapshot(cx))
19092            .max_point()
19093    }
19094
19095    pub fn text(&self, cx: &App) -> String {
19096        self.buffer.read(cx).read(cx).text()
19097    }
19098
19099    pub fn is_empty(&self, cx: &App) -> bool {
19100        self.buffer.read(cx).read(cx).is_empty()
19101    }
19102
19103    pub fn text_option(&self, cx: &App) -> Option<String> {
19104        let text = self.text(cx);
19105        let text = text.trim();
19106
19107        if text.is_empty() {
19108            return None;
19109        }
19110
19111        Some(text.to_string())
19112    }
19113
19114    pub fn set_text(
19115        &mut self,
19116        text: impl Into<Arc<str>>,
19117        window: &mut Window,
19118        cx: &mut Context<Self>,
19119    ) {
19120        self.transact(window, cx, |this, _, cx| {
19121            this.buffer
19122                .read(cx)
19123                .as_singleton()
19124                .expect("you can only call set_text on editors for singleton buffers")
19125                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19126        });
19127    }
19128
19129    pub fn display_text(&self, cx: &mut App) -> String {
19130        self.display_map
19131            .update(cx, |map, cx| map.snapshot(cx))
19132            .text()
19133    }
19134
19135    fn create_minimap(
19136        &self,
19137        minimap_settings: MinimapSettings,
19138        window: &mut Window,
19139        cx: &mut Context<Self>,
19140    ) -> Option<Entity<Self>> {
19141        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19142            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19143    }
19144
19145    fn initialize_new_minimap(
19146        &self,
19147        minimap_settings: MinimapSettings,
19148        window: &mut Window,
19149        cx: &mut Context<Self>,
19150    ) -> Entity<Self> {
19151        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19152
19153        let mut minimap = Editor::new_internal(
19154            EditorMode::Minimap {
19155                parent: cx.weak_entity(),
19156            },
19157            self.buffer.clone(),
19158            None,
19159            Some(self.display_map.clone()),
19160            window,
19161            cx,
19162        );
19163        minimap.scroll_manager.clone_state(&self.scroll_manager);
19164        minimap.set_text_style_refinement(TextStyleRefinement {
19165            font_size: Some(MINIMAP_FONT_SIZE),
19166            font_weight: Some(MINIMAP_FONT_WEIGHT),
19167            ..Default::default()
19168        });
19169        minimap.update_minimap_configuration(minimap_settings, cx);
19170        cx.new(|_| minimap)
19171    }
19172
19173    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19174        let current_line_highlight = minimap_settings
19175            .current_line_highlight
19176            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19177        self.set_current_line_highlight(Some(current_line_highlight));
19178    }
19179
19180    pub fn minimap(&self) -> Option<&Entity<Self>> {
19181        self.minimap
19182            .as_ref()
19183            .filter(|_| self.minimap_visibility.visible())
19184    }
19185
19186    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19187        let mut wrap_guides = smallvec![];
19188
19189        if self.show_wrap_guides == Some(false) {
19190            return wrap_guides;
19191        }
19192
19193        let settings = self.buffer.read(cx).language_settings(cx);
19194        if settings.show_wrap_guides {
19195            match self.soft_wrap_mode(cx) {
19196                SoftWrap::Column(soft_wrap) => {
19197                    wrap_guides.push((soft_wrap as usize, true));
19198                }
19199                SoftWrap::Bounded(soft_wrap) => {
19200                    wrap_guides.push((soft_wrap as usize, true));
19201                }
19202                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19203            }
19204            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19205        }
19206
19207        wrap_guides
19208    }
19209
19210    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19211        let settings = self.buffer.read(cx).language_settings(cx);
19212        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19213        match mode {
19214            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19215                SoftWrap::None
19216            }
19217            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19218            language_settings::SoftWrap::PreferredLineLength => {
19219                SoftWrap::Column(settings.preferred_line_length)
19220            }
19221            language_settings::SoftWrap::Bounded => {
19222                SoftWrap::Bounded(settings.preferred_line_length)
19223            }
19224        }
19225    }
19226
19227    pub fn set_soft_wrap_mode(
19228        &mut self,
19229        mode: language_settings::SoftWrap,
19230
19231        cx: &mut Context<Self>,
19232    ) {
19233        self.soft_wrap_mode_override = Some(mode);
19234        cx.notify();
19235    }
19236
19237    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19238        self.hard_wrap = hard_wrap;
19239        cx.notify();
19240    }
19241
19242    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19243        self.text_style_refinement = Some(style);
19244    }
19245
19246    /// called by the Element so we know what style we were most recently rendered with.
19247    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19248        // We intentionally do not inform the display map about the minimap style
19249        // so that wrapping is not recalculated and stays consistent for the editor
19250        // and its linked minimap.
19251        if !self.mode.is_minimap() {
19252            let font = style.text.font();
19253            let font_size = style.text.font_size.to_pixels(window.rem_size());
19254            let display_map = self
19255                .placeholder_display_map
19256                .as_ref()
19257                .filter(|_| self.is_empty(cx))
19258                .unwrap_or(&self.display_map);
19259
19260            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19261        }
19262        self.style = Some(style);
19263    }
19264
19265    pub fn style(&self) -> Option<&EditorStyle> {
19266        self.style.as_ref()
19267    }
19268
19269    // Called by the element. This method is not designed to be called outside of the editor
19270    // element's layout code because it does not notify when rewrapping is computed synchronously.
19271    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19272        if self.is_empty(cx) {
19273            self.placeholder_display_map
19274                .as_ref()
19275                .map_or(false, |display_map| {
19276                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19277                })
19278        } else {
19279            self.display_map
19280                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19281        }
19282    }
19283
19284    pub fn set_soft_wrap(&mut self) {
19285        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19286    }
19287
19288    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19289        if self.soft_wrap_mode_override.is_some() {
19290            self.soft_wrap_mode_override.take();
19291        } else {
19292            let soft_wrap = match self.soft_wrap_mode(cx) {
19293                SoftWrap::GitDiff => return,
19294                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19295                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19296                    language_settings::SoftWrap::None
19297                }
19298            };
19299            self.soft_wrap_mode_override = Some(soft_wrap);
19300        }
19301        cx.notify();
19302    }
19303
19304    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19305        let Some(workspace) = self.workspace() else {
19306            return;
19307        };
19308        let fs = workspace.read(cx).app_state().fs.clone();
19309        let current_show = TabBarSettings::get_global(cx).show;
19310        update_settings_file(fs, cx, move |setting, _| {
19311            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19312        });
19313    }
19314
19315    pub fn toggle_indent_guides(
19316        &mut self,
19317        _: &ToggleIndentGuides,
19318        _: &mut Window,
19319        cx: &mut Context<Self>,
19320    ) {
19321        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19322            self.buffer
19323                .read(cx)
19324                .language_settings(cx)
19325                .indent_guides
19326                .enabled
19327        });
19328        self.show_indent_guides = Some(!currently_enabled);
19329        cx.notify();
19330    }
19331
19332    fn should_show_indent_guides(&self) -> Option<bool> {
19333        self.show_indent_guides
19334    }
19335
19336    pub fn toggle_line_numbers(
19337        &mut self,
19338        _: &ToggleLineNumbers,
19339        _: &mut Window,
19340        cx: &mut Context<Self>,
19341    ) {
19342        let mut editor_settings = EditorSettings::get_global(cx).clone();
19343        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19344        EditorSettings::override_global(editor_settings, cx);
19345    }
19346
19347    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19348        if let Some(show_line_numbers) = self.show_line_numbers {
19349            return show_line_numbers;
19350        }
19351        EditorSettings::get_global(cx).gutter.line_numbers
19352    }
19353
19354    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19355        self.use_relative_line_numbers
19356            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19357    }
19358
19359    pub fn toggle_relative_line_numbers(
19360        &mut self,
19361        _: &ToggleRelativeLineNumbers,
19362        _: &mut Window,
19363        cx: &mut Context<Self>,
19364    ) {
19365        let is_relative = self.should_use_relative_line_numbers(cx);
19366        self.set_relative_line_number(Some(!is_relative), cx)
19367    }
19368
19369    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19370        self.use_relative_line_numbers = is_relative;
19371        cx.notify();
19372    }
19373
19374    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19375        self.show_gutter = show_gutter;
19376        cx.notify();
19377    }
19378
19379    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19380        self.show_scrollbars = ScrollbarAxes {
19381            horizontal: show,
19382            vertical: show,
19383        };
19384        cx.notify();
19385    }
19386
19387    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19388        self.show_scrollbars.vertical = show;
19389        cx.notify();
19390    }
19391
19392    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19393        self.show_scrollbars.horizontal = show;
19394        cx.notify();
19395    }
19396
19397    pub fn set_minimap_visibility(
19398        &mut self,
19399        minimap_visibility: MinimapVisibility,
19400        window: &mut Window,
19401        cx: &mut Context<Self>,
19402    ) {
19403        if self.minimap_visibility != minimap_visibility {
19404            if minimap_visibility.visible() && self.minimap.is_none() {
19405                let minimap_settings = EditorSettings::get_global(cx).minimap;
19406                self.minimap =
19407                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19408            }
19409            self.minimap_visibility = minimap_visibility;
19410            cx.notify();
19411        }
19412    }
19413
19414    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19415        self.set_show_scrollbars(false, cx);
19416        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19417    }
19418
19419    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19420        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19421    }
19422
19423    /// Normally the text in full mode and auto height editors is padded on the
19424    /// left side by roughly half a character width for improved hit testing.
19425    ///
19426    /// Use this method to disable this for cases where this is not wanted (e.g.
19427    /// if you want to align the editor text with some other text above or below)
19428    /// or if you want to add this padding to single-line editors.
19429    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19430        self.offset_content = offset_content;
19431        cx.notify();
19432    }
19433
19434    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19435        self.show_line_numbers = Some(show_line_numbers);
19436        cx.notify();
19437    }
19438
19439    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19440        self.disable_expand_excerpt_buttons = true;
19441        cx.notify();
19442    }
19443
19444    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19445        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19446        cx.notify();
19447    }
19448
19449    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19450        self.show_code_actions = Some(show_code_actions);
19451        cx.notify();
19452    }
19453
19454    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19455        self.show_runnables = Some(show_runnables);
19456        cx.notify();
19457    }
19458
19459    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19460        self.show_breakpoints = Some(show_breakpoints);
19461        cx.notify();
19462    }
19463
19464    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19465        if self.display_map.read(cx).masked != masked {
19466            self.display_map.update(cx, |map, _| map.masked = masked);
19467        }
19468        cx.notify()
19469    }
19470
19471    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19472        self.show_wrap_guides = Some(show_wrap_guides);
19473        cx.notify();
19474    }
19475
19476    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19477        self.show_indent_guides = Some(show_indent_guides);
19478        cx.notify();
19479    }
19480
19481    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19482        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19483            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19484                && let Some(dir) = file.abs_path(cx).parent()
19485            {
19486                return Some(dir.to_owned());
19487            }
19488        }
19489
19490        None
19491    }
19492
19493    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19494        self.active_excerpt(cx)?
19495            .1
19496            .read(cx)
19497            .file()
19498            .and_then(|f| f.as_local())
19499    }
19500
19501    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19502        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19503            let buffer = buffer.read(cx);
19504            if let Some(project_path) = buffer.project_path(cx) {
19505                let project = self.project()?.read(cx);
19506                project.absolute_path(&project_path, cx)
19507            } else {
19508                buffer
19509                    .file()
19510                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19511            }
19512        })
19513    }
19514
19515    pub fn reveal_in_finder(
19516        &mut self,
19517        _: &RevealInFileManager,
19518        _window: &mut Window,
19519        cx: &mut Context<Self>,
19520    ) {
19521        if let Some(target) = self.target_file(cx) {
19522            cx.reveal_path(&target.abs_path(cx));
19523        }
19524    }
19525
19526    pub fn copy_path(
19527        &mut self,
19528        _: &zed_actions::workspace::CopyPath,
19529        _window: &mut Window,
19530        cx: &mut Context<Self>,
19531    ) {
19532        if let Some(path) = self.target_file_abs_path(cx)
19533            && let Some(path) = path.to_str()
19534        {
19535            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19536        } else {
19537            cx.propagate();
19538        }
19539    }
19540
19541    pub fn copy_relative_path(
19542        &mut self,
19543        _: &zed_actions::workspace::CopyRelativePath,
19544        _window: &mut Window,
19545        cx: &mut Context<Self>,
19546    ) {
19547        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19548            let project = self.project()?.read(cx);
19549            let path = buffer.read(cx).file()?.path();
19550            let path = path.display(project.path_style(cx));
19551            Some(path)
19552        }) {
19553            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19554        } else {
19555            cx.propagate();
19556        }
19557    }
19558
19559    /// Returns the project path for the editor's buffer, if any buffer is
19560    /// opened in the editor.
19561    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19562        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19563            buffer.read(cx).project_path(cx)
19564        } else {
19565            None
19566        }
19567    }
19568
19569    // Returns true if the editor handled a go-to-line request
19570    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19571        maybe!({
19572            let breakpoint_store = self.breakpoint_store.as_ref()?;
19573
19574            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19575            else {
19576                self.clear_row_highlights::<ActiveDebugLine>();
19577                return None;
19578            };
19579
19580            let position = active_stack_frame.position;
19581            let buffer_id = position.buffer_id?;
19582            let snapshot = self
19583                .project
19584                .as_ref()?
19585                .read(cx)
19586                .buffer_for_id(buffer_id, cx)?
19587                .read(cx)
19588                .snapshot();
19589
19590            let mut handled = false;
19591            for (id, ExcerptRange { context, .. }) in
19592                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19593            {
19594                if context.start.cmp(&position, &snapshot).is_ge()
19595                    || context.end.cmp(&position, &snapshot).is_lt()
19596                {
19597                    continue;
19598                }
19599                let snapshot = self.buffer.read(cx).snapshot(cx);
19600                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19601
19602                handled = true;
19603                self.clear_row_highlights::<ActiveDebugLine>();
19604
19605                self.go_to_line::<ActiveDebugLine>(
19606                    multibuffer_anchor,
19607                    Some(cx.theme().colors().editor_debugger_active_line_background),
19608                    window,
19609                    cx,
19610                );
19611
19612                cx.notify();
19613            }
19614
19615            handled.then_some(())
19616        })
19617        .is_some()
19618    }
19619
19620    pub fn copy_file_name_without_extension(
19621        &mut self,
19622        _: &CopyFileNameWithoutExtension,
19623        _: &mut Window,
19624        cx: &mut Context<Self>,
19625    ) {
19626        if let Some(file) = self.target_file(cx)
19627            && let Some(file_stem) = file.path().file_stem()
19628        {
19629            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19630        }
19631    }
19632
19633    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19634        if let Some(file) = self.target_file(cx)
19635            && let Some(name) = file.path().file_name()
19636        {
19637            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19638        }
19639    }
19640
19641    pub fn toggle_git_blame(
19642        &mut self,
19643        _: &::git::Blame,
19644        window: &mut Window,
19645        cx: &mut Context<Self>,
19646    ) {
19647        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19648
19649        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19650            self.start_git_blame(true, window, cx);
19651        }
19652
19653        cx.notify();
19654    }
19655
19656    pub fn toggle_git_blame_inline(
19657        &mut self,
19658        _: &ToggleGitBlameInline,
19659        window: &mut Window,
19660        cx: &mut Context<Self>,
19661    ) {
19662        self.toggle_git_blame_inline_internal(true, window, cx);
19663        cx.notify();
19664    }
19665
19666    pub fn open_git_blame_commit(
19667        &mut self,
19668        _: &OpenGitBlameCommit,
19669        window: &mut Window,
19670        cx: &mut Context<Self>,
19671    ) {
19672        self.open_git_blame_commit_internal(window, cx);
19673    }
19674
19675    fn open_git_blame_commit_internal(
19676        &mut self,
19677        window: &mut Window,
19678        cx: &mut Context<Self>,
19679    ) -> Option<()> {
19680        let blame = self.blame.as_ref()?;
19681        let snapshot = self.snapshot(window, cx);
19682        let cursor = self
19683            .selections
19684            .newest::<Point>(&snapshot.display_snapshot)
19685            .head();
19686        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19687        let (_, blame_entry) = blame
19688            .update(cx, |blame, cx| {
19689                blame
19690                    .blame_for_rows(
19691                        &[RowInfo {
19692                            buffer_id: Some(buffer.remote_id()),
19693                            buffer_row: Some(point.row),
19694                            ..Default::default()
19695                        }],
19696                        cx,
19697                    )
19698                    .next()
19699            })
19700            .flatten()?;
19701        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19702        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19703        let workspace = self.workspace()?.downgrade();
19704        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19705        None
19706    }
19707
19708    pub fn git_blame_inline_enabled(&self) -> bool {
19709        self.git_blame_inline_enabled
19710    }
19711
19712    pub fn toggle_selection_menu(
19713        &mut self,
19714        _: &ToggleSelectionMenu,
19715        _: &mut Window,
19716        cx: &mut Context<Self>,
19717    ) {
19718        self.show_selection_menu = self
19719            .show_selection_menu
19720            .map(|show_selections_menu| !show_selections_menu)
19721            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19722
19723        cx.notify();
19724    }
19725
19726    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19727        self.show_selection_menu
19728            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19729    }
19730
19731    fn start_git_blame(
19732        &mut self,
19733        user_triggered: bool,
19734        window: &mut Window,
19735        cx: &mut Context<Self>,
19736    ) {
19737        if let Some(project) = self.project() {
19738            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19739                && buffer.read(cx).file().is_none()
19740            {
19741                return;
19742            }
19743
19744            let focused = self.focus_handle(cx).contains_focused(window, cx);
19745
19746            let project = project.clone();
19747            let blame = cx
19748                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19749            self.blame_subscription =
19750                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19751            self.blame = Some(blame);
19752        }
19753    }
19754
19755    fn toggle_git_blame_inline_internal(
19756        &mut self,
19757        user_triggered: bool,
19758        window: &mut Window,
19759        cx: &mut Context<Self>,
19760    ) {
19761        if self.git_blame_inline_enabled {
19762            self.git_blame_inline_enabled = false;
19763            self.show_git_blame_inline = false;
19764            self.show_git_blame_inline_delay_task.take();
19765        } else {
19766            self.git_blame_inline_enabled = true;
19767            self.start_git_blame_inline(user_triggered, window, cx);
19768        }
19769
19770        cx.notify();
19771    }
19772
19773    fn start_git_blame_inline(
19774        &mut self,
19775        user_triggered: bool,
19776        window: &mut Window,
19777        cx: &mut Context<Self>,
19778    ) {
19779        self.start_git_blame(user_triggered, window, cx);
19780
19781        if ProjectSettings::get_global(cx)
19782            .git
19783            .inline_blame_delay()
19784            .is_some()
19785        {
19786            self.start_inline_blame_timer(window, cx);
19787        } else {
19788            self.show_git_blame_inline = true
19789        }
19790    }
19791
19792    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19793        self.blame.as_ref()
19794    }
19795
19796    pub fn show_git_blame_gutter(&self) -> bool {
19797        self.show_git_blame_gutter
19798    }
19799
19800    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19801        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19802    }
19803
19804    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19805        self.show_git_blame_inline
19806            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19807            && !self.newest_selection_head_on_empty_line(cx)
19808            && self.has_blame_entries(cx)
19809    }
19810
19811    fn has_blame_entries(&self, cx: &App) -> bool {
19812        self.blame()
19813            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19814    }
19815
19816    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19817        let cursor_anchor = self.selections.newest_anchor().head();
19818
19819        let snapshot = self.buffer.read(cx).snapshot(cx);
19820        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19821
19822        snapshot.line_len(buffer_row) == 0
19823    }
19824
19825    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19826        let buffer_and_selection = maybe!({
19827            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19828            let selection_range = selection.range();
19829
19830            let multi_buffer = self.buffer().read(cx);
19831            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19832            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19833
19834            let (buffer, range, _) = if selection.reversed {
19835                buffer_ranges.first()
19836            } else {
19837                buffer_ranges.last()
19838            }?;
19839
19840            let selection = text::ToPoint::to_point(&range.start, buffer).row
19841                ..text::ToPoint::to_point(&range.end, buffer).row;
19842            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19843        });
19844
19845        let Some((buffer, selection)) = buffer_and_selection else {
19846            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19847        };
19848
19849        let Some(project) = self.project() else {
19850            return Task::ready(Err(anyhow!("editor does not have project")));
19851        };
19852
19853        project.update(cx, |project, cx| {
19854            project.get_permalink_to_line(&buffer, selection, cx)
19855        })
19856    }
19857
19858    pub fn copy_permalink_to_line(
19859        &mut self,
19860        _: &CopyPermalinkToLine,
19861        window: &mut Window,
19862        cx: &mut Context<Self>,
19863    ) {
19864        let permalink_task = self.get_permalink_to_line(cx);
19865        let workspace = self.workspace();
19866
19867        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19868            Ok(permalink) => {
19869                cx.update(|_, cx| {
19870                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19871                })
19872                .ok();
19873            }
19874            Err(err) => {
19875                let message = format!("Failed to copy permalink: {err}");
19876
19877                anyhow::Result::<()>::Err(err).log_err();
19878
19879                if let Some(workspace) = workspace {
19880                    workspace
19881                        .update_in(cx, |workspace, _, cx| {
19882                            struct CopyPermalinkToLine;
19883
19884                            workspace.show_toast(
19885                                Toast::new(
19886                                    NotificationId::unique::<CopyPermalinkToLine>(),
19887                                    message,
19888                                ),
19889                                cx,
19890                            )
19891                        })
19892                        .ok();
19893                }
19894            }
19895        })
19896        .detach();
19897    }
19898
19899    pub fn copy_file_location(
19900        &mut self,
19901        _: &CopyFileLocation,
19902        _: &mut Window,
19903        cx: &mut Context<Self>,
19904    ) {
19905        let selection = self
19906            .selections
19907            .newest::<Point>(&self.display_snapshot(cx))
19908            .start
19909            .row
19910            + 1;
19911        if let Some(file) = self.target_file(cx) {
19912            let path = file.path().display(file.path_style(cx));
19913            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19914        }
19915    }
19916
19917    pub fn open_permalink_to_line(
19918        &mut self,
19919        _: &OpenPermalinkToLine,
19920        window: &mut Window,
19921        cx: &mut Context<Self>,
19922    ) {
19923        let permalink_task = self.get_permalink_to_line(cx);
19924        let workspace = self.workspace();
19925
19926        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19927            Ok(permalink) => {
19928                cx.update(|_, cx| {
19929                    cx.open_url(permalink.as_ref());
19930                })
19931                .ok();
19932            }
19933            Err(err) => {
19934                let message = format!("Failed to open permalink: {err}");
19935
19936                anyhow::Result::<()>::Err(err).log_err();
19937
19938                if let Some(workspace) = workspace {
19939                    workspace
19940                        .update(cx, |workspace, cx| {
19941                            struct OpenPermalinkToLine;
19942
19943                            workspace.show_toast(
19944                                Toast::new(
19945                                    NotificationId::unique::<OpenPermalinkToLine>(),
19946                                    message,
19947                                ),
19948                                cx,
19949                            )
19950                        })
19951                        .ok();
19952                }
19953            }
19954        })
19955        .detach();
19956    }
19957
19958    pub fn insert_uuid_v4(
19959        &mut self,
19960        _: &InsertUuidV4,
19961        window: &mut Window,
19962        cx: &mut Context<Self>,
19963    ) {
19964        self.insert_uuid(UuidVersion::V4, window, cx);
19965    }
19966
19967    pub fn insert_uuid_v7(
19968        &mut self,
19969        _: &InsertUuidV7,
19970        window: &mut Window,
19971        cx: &mut Context<Self>,
19972    ) {
19973        self.insert_uuid(UuidVersion::V7, window, cx);
19974    }
19975
19976    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19977        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19978        self.transact(window, cx, |this, window, cx| {
19979            let edits = this
19980                .selections
19981                .all::<Point>(&this.display_snapshot(cx))
19982                .into_iter()
19983                .map(|selection| {
19984                    let uuid = match version {
19985                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19986                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19987                    };
19988
19989                    (selection.range(), uuid.to_string())
19990                });
19991            this.edit(edits, cx);
19992            this.refresh_edit_prediction(true, false, window, cx);
19993        });
19994    }
19995
19996    pub fn open_selections_in_multibuffer(
19997        &mut self,
19998        _: &OpenSelectionsInMultibuffer,
19999        window: &mut Window,
20000        cx: &mut Context<Self>,
20001    ) {
20002        let multibuffer = self.buffer.read(cx);
20003
20004        let Some(buffer) = multibuffer.as_singleton() else {
20005            return;
20006        };
20007
20008        let Some(workspace) = self.workspace() else {
20009            return;
20010        };
20011
20012        let title = multibuffer.title(cx).to_string();
20013
20014        let locations = self
20015            .selections
20016            .all_anchors(cx)
20017            .iter()
20018            .map(|selection| {
20019                (
20020                    buffer.clone(),
20021                    (selection.start.text_anchor..selection.end.text_anchor)
20022                        .to_point(buffer.read(cx)),
20023                )
20024            })
20025            .into_group_map();
20026
20027        cx.spawn_in(window, async move |_, cx| {
20028            workspace.update_in(cx, |workspace, window, cx| {
20029                Self::open_locations_in_multibuffer(
20030                    workspace,
20031                    locations,
20032                    format!("Selections for '{title}'"),
20033                    false,
20034                    MultibufferSelectionMode::All,
20035                    window,
20036                    cx,
20037                );
20038            })
20039        })
20040        .detach();
20041    }
20042
20043    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20044    /// last highlight added will be used.
20045    ///
20046    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20047    pub fn highlight_rows<T: 'static>(
20048        &mut self,
20049        range: Range<Anchor>,
20050        color: Hsla,
20051        options: RowHighlightOptions,
20052        cx: &mut Context<Self>,
20053    ) {
20054        let snapshot = self.buffer().read(cx).snapshot(cx);
20055        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20056        let ix = row_highlights.binary_search_by(|highlight| {
20057            Ordering::Equal
20058                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20059                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20060        });
20061
20062        if let Err(mut ix) = ix {
20063            let index = post_inc(&mut self.highlight_order);
20064
20065            // If this range intersects with the preceding highlight, then merge it with
20066            // the preceding highlight. Otherwise insert a new highlight.
20067            let mut merged = false;
20068            if ix > 0 {
20069                let prev_highlight = &mut row_highlights[ix - 1];
20070                if prev_highlight
20071                    .range
20072                    .end
20073                    .cmp(&range.start, &snapshot)
20074                    .is_ge()
20075                {
20076                    ix -= 1;
20077                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20078                        prev_highlight.range.end = range.end;
20079                    }
20080                    merged = true;
20081                    prev_highlight.index = index;
20082                    prev_highlight.color = color;
20083                    prev_highlight.options = options;
20084                }
20085            }
20086
20087            if !merged {
20088                row_highlights.insert(
20089                    ix,
20090                    RowHighlight {
20091                        range,
20092                        index,
20093                        color,
20094                        options,
20095                        type_id: TypeId::of::<T>(),
20096                    },
20097                );
20098            }
20099
20100            // If any of the following highlights intersect with this one, merge them.
20101            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20102                let highlight = &row_highlights[ix];
20103                if next_highlight
20104                    .range
20105                    .start
20106                    .cmp(&highlight.range.end, &snapshot)
20107                    .is_le()
20108                {
20109                    if next_highlight
20110                        .range
20111                        .end
20112                        .cmp(&highlight.range.end, &snapshot)
20113                        .is_gt()
20114                    {
20115                        row_highlights[ix].range.end = next_highlight.range.end;
20116                    }
20117                    row_highlights.remove(ix + 1);
20118                } else {
20119                    break;
20120                }
20121            }
20122        }
20123    }
20124
20125    /// Remove any highlighted row ranges of the given type that intersect the
20126    /// given ranges.
20127    pub fn remove_highlighted_rows<T: 'static>(
20128        &mut self,
20129        ranges_to_remove: Vec<Range<Anchor>>,
20130        cx: &mut Context<Self>,
20131    ) {
20132        let snapshot = self.buffer().read(cx).snapshot(cx);
20133        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20134        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20135        row_highlights.retain(|highlight| {
20136            while let Some(range_to_remove) = ranges_to_remove.peek() {
20137                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20138                    Ordering::Less | Ordering::Equal => {
20139                        ranges_to_remove.next();
20140                    }
20141                    Ordering::Greater => {
20142                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20143                            Ordering::Less | Ordering::Equal => {
20144                                return false;
20145                            }
20146                            Ordering::Greater => break,
20147                        }
20148                    }
20149                }
20150            }
20151
20152            true
20153        })
20154    }
20155
20156    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20157    pub fn clear_row_highlights<T: 'static>(&mut self) {
20158        self.highlighted_rows.remove(&TypeId::of::<T>());
20159    }
20160
20161    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20162    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20163        self.highlighted_rows
20164            .get(&TypeId::of::<T>())
20165            .map_or(&[] as &[_], |vec| vec.as_slice())
20166            .iter()
20167            .map(|highlight| (highlight.range.clone(), highlight.color))
20168    }
20169
20170    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20171    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20172    /// Allows to ignore certain kinds of highlights.
20173    pub fn highlighted_display_rows(
20174        &self,
20175        window: &mut Window,
20176        cx: &mut App,
20177    ) -> BTreeMap<DisplayRow, LineHighlight> {
20178        let snapshot = self.snapshot(window, cx);
20179        let mut used_highlight_orders = HashMap::default();
20180        self.highlighted_rows
20181            .iter()
20182            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20183            .fold(
20184                BTreeMap::<DisplayRow, LineHighlight>::new(),
20185                |mut unique_rows, highlight| {
20186                    let start = highlight.range.start.to_display_point(&snapshot);
20187                    let end = highlight.range.end.to_display_point(&snapshot);
20188                    let start_row = start.row().0;
20189                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20190                        && end.column() == 0
20191                    {
20192                        end.row().0.saturating_sub(1)
20193                    } else {
20194                        end.row().0
20195                    };
20196                    for row in start_row..=end_row {
20197                        let used_index =
20198                            used_highlight_orders.entry(row).or_insert(highlight.index);
20199                        if highlight.index >= *used_index {
20200                            *used_index = highlight.index;
20201                            unique_rows.insert(
20202                                DisplayRow(row),
20203                                LineHighlight {
20204                                    include_gutter: highlight.options.include_gutter,
20205                                    border: None,
20206                                    background: highlight.color.into(),
20207                                    type_id: Some(highlight.type_id),
20208                                },
20209                            );
20210                        }
20211                    }
20212                    unique_rows
20213                },
20214            )
20215    }
20216
20217    pub fn highlighted_display_row_for_autoscroll(
20218        &self,
20219        snapshot: &DisplaySnapshot,
20220    ) -> Option<DisplayRow> {
20221        self.highlighted_rows
20222            .values()
20223            .flat_map(|highlighted_rows| highlighted_rows.iter())
20224            .filter_map(|highlight| {
20225                if highlight.options.autoscroll {
20226                    Some(highlight.range.start.to_display_point(snapshot).row())
20227                } else {
20228                    None
20229                }
20230            })
20231            .min()
20232    }
20233
20234    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20235        self.highlight_background::<SearchWithinRange>(
20236            ranges,
20237            |colors| colors.colors().editor_document_highlight_read_background,
20238            cx,
20239        )
20240    }
20241
20242    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20243        self.breadcrumb_header = Some(new_header);
20244    }
20245
20246    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20247        self.clear_background_highlights::<SearchWithinRange>(cx);
20248    }
20249
20250    pub fn highlight_background<T: 'static>(
20251        &mut self,
20252        ranges: &[Range<Anchor>],
20253        color_fetcher: fn(&Theme) -> Hsla,
20254        cx: &mut Context<Self>,
20255    ) {
20256        self.background_highlights.insert(
20257            HighlightKey::Type(TypeId::of::<T>()),
20258            (color_fetcher, Arc::from(ranges)),
20259        );
20260        self.scrollbar_marker_state.dirty = true;
20261        cx.notify();
20262    }
20263
20264    pub fn highlight_background_key<T: 'static>(
20265        &mut self,
20266        key: usize,
20267        ranges: &[Range<Anchor>],
20268        color_fetcher: fn(&Theme) -> Hsla,
20269        cx: &mut Context<Self>,
20270    ) {
20271        self.background_highlights.insert(
20272            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20273            (color_fetcher, Arc::from(ranges)),
20274        );
20275        self.scrollbar_marker_state.dirty = true;
20276        cx.notify();
20277    }
20278
20279    pub fn clear_background_highlights<T: 'static>(
20280        &mut self,
20281        cx: &mut Context<Self>,
20282    ) -> Option<BackgroundHighlight> {
20283        let text_highlights = self
20284            .background_highlights
20285            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20286        if !text_highlights.1.is_empty() {
20287            self.scrollbar_marker_state.dirty = true;
20288            cx.notify();
20289        }
20290        Some(text_highlights)
20291    }
20292
20293    pub fn highlight_gutter<T: 'static>(
20294        &mut self,
20295        ranges: impl Into<Vec<Range<Anchor>>>,
20296        color_fetcher: fn(&App) -> Hsla,
20297        cx: &mut Context<Self>,
20298    ) {
20299        self.gutter_highlights
20300            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20301        cx.notify();
20302    }
20303
20304    pub fn clear_gutter_highlights<T: 'static>(
20305        &mut self,
20306        cx: &mut Context<Self>,
20307    ) -> Option<GutterHighlight> {
20308        cx.notify();
20309        self.gutter_highlights.remove(&TypeId::of::<T>())
20310    }
20311
20312    pub fn insert_gutter_highlight<T: 'static>(
20313        &mut self,
20314        range: Range<Anchor>,
20315        color_fetcher: fn(&App) -> Hsla,
20316        cx: &mut Context<Self>,
20317    ) {
20318        let snapshot = self.buffer().read(cx).snapshot(cx);
20319        let mut highlights = self
20320            .gutter_highlights
20321            .remove(&TypeId::of::<T>())
20322            .map(|(_, highlights)| highlights)
20323            .unwrap_or_default();
20324        let ix = highlights.binary_search_by(|highlight| {
20325            Ordering::Equal
20326                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20327                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20328        });
20329        if let Err(ix) = ix {
20330            highlights.insert(ix, range);
20331        }
20332        self.gutter_highlights
20333            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20334    }
20335
20336    pub fn remove_gutter_highlights<T: 'static>(
20337        &mut self,
20338        ranges_to_remove: Vec<Range<Anchor>>,
20339        cx: &mut Context<Self>,
20340    ) {
20341        let snapshot = self.buffer().read(cx).snapshot(cx);
20342        let Some((color_fetcher, mut gutter_highlights)) =
20343            self.gutter_highlights.remove(&TypeId::of::<T>())
20344        else {
20345            return;
20346        };
20347        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20348        gutter_highlights.retain(|highlight| {
20349            while let Some(range_to_remove) = ranges_to_remove.peek() {
20350                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20351                    Ordering::Less | Ordering::Equal => {
20352                        ranges_to_remove.next();
20353                    }
20354                    Ordering::Greater => {
20355                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20356                            Ordering::Less | Ordering::Equal => {
20357                                return false;
20358                            }
20359                            Ordering::Greater => break,
20360                        }
20361                    }
20362                }
20363            }
20364
20365            true
20366        });
20367        self.gutter_highlights
20368            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20369    }
20370
20371    #[cfg(feature = "test-support")]
20372    pub fn all_text_highlights(
20373        &self,
20374        window: &mut Window,
20375        cx: &mut Context<Self>,
20376    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20377        let snapshot = self.snapshot(window, cx);
20378        self.display_map.update(cx, |display_map, _| {
20379            display_map
20380                .all_text_highlights()
20381                .map(|highlight| {
20382                    let (style, ranges) = highlight.as_ref();
20383                    (
20384                        *style,
20385                        ranges
20386                            .iter()
20387                            .map(|range| range.clone().to_display_points(&snapshot))
20388                            .collect(),
20389                    )
20390                })
20391                .collect()
20392        })
20393    }
20394
20395    #[cfg(feature = "test-support")]
20396    pub fn all_text_background_highlights(
20397        &self,
20398        window: &mut Window,
20399        cx: &mut Context<Self>,
20400    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20401        let snapshot = self.snapshot(window, cx);
20402        let buffer = &snapshot.buffer_snapshot();
20403        let start = buffer.anchor_before(0);
20404        let end = buffer.anchor_after(buffer.len());
20405        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20406    }
20407
20408    #[cfg(any(test, feature = "test-support"))]
20409    pub fn sorted_background_highlights_in_range(
20410        &self,
20411        search_range: Range<Anchor>,
20412        display_snapshot: &DisplaySnapshot,
20413        theme: &Theme,
20414    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20415        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20416        res.sort_by(|a, b| {
20417            a.0.start
20418                .cmp(&b.0.start)
20419                .then_with(|| a.0.end.cmp(&b.0.end))
20420                .then_with(|| a.1.cmp(&b.1))
20421        });
20422        res
20423    }
20424
20425    #[cfg(feature = "test-support")]
20426    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20427        let snapshot = self.buffer().read(cx).snapshot(cx);
20428
20429        let highlights = self
20430            .background_highlights
20431            .get(&HighlightKey::Type(TypeId::of::<
20432                items::BufferSearchHighlights,
20433            >()));
20434
20435        if let Some((_color, ranges)) = highlights {
20436            ranges
20437                .iter()
20438                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20439                .collect_vec()
20440        } else {
20441            vec![]
20442        }
20443    }
20444
20445    fn document_highlights_for_position<'a>(
20446        &'a self,
20447        position: Anchor,
20448        buffer: &'a MultiBufferSnapshot,
20449    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20450        let read_highlights = self
20451            .background_highlights
20452            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20453            .map(|h| &h.1);
20454        let write_highlights = self
20455            .background_highlights
20456            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20457            .map(|h| &h.1);
20458        let left_position = position.bias_left(buffer);
20459        let right_position = position.bias_right(buffer);
20460        read_highlights
20461            .into_iter()
20462            .chain(write_highlights)
20463            .flat_map(move |ranges| {
20464                let start_ix = match ranges.binary_search_by(|probe| {
20465                    let cmp = probe.end.cmp(&left_position, buffer);
20466                    if cmp.is_ge() {
20467                        Ordering::Greater
20468                    } else {
20469                        Ordering::Less
20470                    }
20471                }) {
20472                    Ok(i) | Err(i) => i,
20473                };
20474
20475                ranges[start_ix..]
20476                    .iter()
20477                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20478            })
20479    }
20480
20481    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20482        self.background_highlights
20483            .get(&HighlightKey::Type(TypeId::of::<T>()))
20484            .is_some_and(|(_, highlights)| !highlights.is_empty())
20485    }
20486
20487    /// Returns all background highlights for a given range.
20488    ///
20489    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20490    pub fn background_highlights_in_range(
20491        &self,
20492        search_range: Range<Anchor>,
20493        display_snapshot: &DisplaySnapshot,
20494        theme: &Theme,
20495    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20496        let mut results = Vec::new();
20497        for (color_fetcher, ranges) in self.background_highlights.values() {
20498            let color = color_fetcher(theme);
20499            let start_ix = match ranges.binary_search_by(|probe| {
20500                let cmp = probe
20501                    .end
20502                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20503                if cmp.is_gt() {
20504                    Ordering::Greater
20505                } else {
20506                    Ordering::Less
20507                }
20508            }) {
20509                Ok(i) | Err(i) => i,
20510            };
20511            for range in &ranges[start_ix..] {
20512                if range
20513                    .start
20514                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20515                    .is_ge()
20516                {
20517                    break;
20518                }
20519
20520                let start = range.start.to_display_point(display_snapshot);
20521                let end = range.end.to_display_point(display_snapshot);
20522                results.push((start..end, color))
20523            }
20524        }
20525        results
20526    }
20527
20528    pub fn gutter_highlights_in_range(
20529        &self,
20530        search_range: Range<Anchor>,
20531        display_snapshot: &DisplaySnapshot,
20532        cx: &App,
20533    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20534        let mut results = Vec::new();
20535        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20536            let color = color_fetcher(cx);
20537            let start_ix = match ranges.binary_search_by(|probe| {
20538                let cmp = probe
20539                    .end
20540                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20541                if cmp.is_gt() {
20542                    Ordering::Greater
20543                } else {
20544                    Ordering::Less
20545                }
20546            }) {
20547                Ok(i) | Err(i) => i,
20548            };
20549            for range in &ranges[start_ix..] {
20550                if range
20551                    .start
20552                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20553                    .is_ge()
20554                {
20555                    break;
20556                }
20557
20558                let start = range.start.to_display_point(display_snapshot);
20559                let end = range.end.to_display_point(display_snapshot);
20560                results.push((start..end, color))
20561            }
20562        }
20563        results
20564    }
20565
20566    /// Get the text ranges corresponding to the redaction query
20567    pub fn redacted_ranges(
20568        &self,
20569        search_range: Range<Anchor>,
20570        display_snapshot: &DisplaySnapshot,
20571        cx: &App,
20572    ) -> Vec<Range<DisplayPoint>> {
20573        display_snapshot
20574            .buffer_snapshot()
20575            .redacted_ranges(search_range, |file| {
20576                if let Some(file) = file {
20577                    file.is_private()
20578                        && EditorSettings::get(
20579                            Some(SettingsLocation {
20580                                worktree_id: file.worktree_id(cx),
20581                                path: file.path().as_ref(),
20582                            }),
20583                            cx,
20584                        )
20585                        .redact_private_values
20586                } else {
20587                    false
20588                }
20589            })
20590            .map(|range| {
20591                range.start.to_display_point(display_snapshot)
20592                    ..range.end.to_display_point(display_snapshot)
20593            })
20594            .collect()
20595    }
20596
20597    pub fn highlight_text_key<T: 'static>(
20598        &mut self,
20599        key: usize,
20600        ranges: Vec<Range<Anchor>>,
20601        style: HighlightStyle,
20602        cx: &mut Context<Self>,
20603    ) {
20604        self.display_map.update(cx, |map, _| {
20605            map.highlight_text(
20606                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20607                ranges,
20608                style,
20609            );
20610        });
20611        cx.notify();
20612    }
20613
20614    pub fn highlight_text<T: 'static>(
20615        &mut self,
20616        ranges: Vec<Range<Anchor>>,
20617        style: HighlightStyle,
20618        cx: &mut Context<Self>,
20619    ) {
20620        self.display_map.update(cx, |map, _| {
20621            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20622        });
20623        cx.notify();
20624    }
20625
20626    pub fn text_highlights<'a, T: 'static>(
20627        &'a self,
20628        cx: &'a App,
20629    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20630        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20631    }
20632
20633    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20634        let cleared = self
20635            .display_map
20636            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20637        if cleared {
20638            cx.notify();
20639        }
20640    }
20641
20642    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20643        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20644            && self.focus_handle.is_focused(window)
20645    }
20646
20647    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20648        self.show_cursor_when_unfocused = is_enabled;
20649        cx.notify();
20650    }
20651
20652    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20653        cx.notify();
20654    }
20655
20656    fn on_debug_session_event(
20657        &mut self,
20658        _session: Entity<Session>,
20659        event: &SessionEvent,
20660        cx: &mut Context<Self>,
20661    ) {
20662        if let SessionEvent::InvalidateInlineValue = event {
20663            self.refresh_inline_values(cx);
20664        }
20665    }
20666
20667    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20668        let Some(project) = self.project.clone() else {
20669            return;
20670        };
20671
20672        if !self.inline_value_cache.enabled {
20673            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20674            self.splice_inlays(&inlays, Vec::new(), cx);
20675            return;
20676        }
20677
20678        let current_execution_position = self
20679            .highlighted_rows
20680            .get(&TypeId::of::<ActiveDebugLine>())
20681            .and_then(|lines| lines.last().map(|line| line.range.end));
20682
20683        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20684            let inline_values = editor
20685                .update(cx, |editor, cx| {
20686                    let Some(current_execution_position) = current_execution_position else {
20687                        return Some(Task::ready(Ok(Vec::new())));
20688                    };
20689
20690                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20691                        let snapshot = buffer.snapshot(cx);
20692
20693                        let excerpt = snapshot.excerpt_containing(
20694                            current_execution_position..current_execution_position,
20695                        )?;
20696
20697                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20698                    })?;
20699
20700                    let range =
20701                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20702
20703                    project.inline_values(buffer, range, cx)
20704                })
20705                .ok()
20706                .flatten()?
20707                .await
20708                .context("refreshing debugger inlays")
20709                .log_err()?;
20710
20711            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20712
20713            for (buffer_id, inline_value) in inline_values
20714                .into_iter()
20715                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20716            {
20717                buffer_inline_values
20718                    .entry(buffer_id)
20719                    .or_default()
20720                    .push(inline_value);
20721            }
20722
20723            editor
20724                .update(cx, |editor, cx| {
20725                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20726                    let mut new_inlays = Vec::default();
20727
20728                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20729                        let buffer_id = buffer_snapshot.remote_id();
20730                        buffer_inline_values
20731                            .get(&buffer_id)
20732                            .into_iter()
20733                            .flatten()
20734                            .for_each(|hint| {
20735                                let inlay = Inlay::debugger(
20736                                    post_inc(&mut editor.next_inlay_id),
20737                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20738                                    hint.text(),
20739                                );
20740                                if !inlay.text().chars().contains(&'\n') {
20741                                    new_inlays.push(inlay);
20742                                }
20743                            });
20744                    }
20745
20746                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20747                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20748
20749                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20750                })
20751                .ok()?;
20752            Some(())
20753        });
20754    }
20755
20756    fn on_buffer_event(
20757        &mut self,
20758        multibuffer: &Entity<MultiBuffer>,
20759        event: &multi_buffer::Event,
20760        window: &mut Window,
20761        cx: &mut Context<Self>,
20762    ) {
20763        match event {
20764            multi_buffer::Event::Edited { edited_buffer } => {
20765                self.scrollbar_marker_state.dirty = true;
20766                self.active_indent_guides_state.dirty = true;
20767                self.refresh_active_diagnostics(cx);
20768                self.refresh_code_actions(window, cx);
20769                self.refresh_selected_text_highlights(true, window, cx);
20770                self.refresh_single_line_folds(window, cx);
20771                self.refresh_matching_bracket_highlights(window, cx);
20772                if self.has_active_edit_prediction() {
20773                    self.update_visible_edit_prediction(window, cx);
20774                }
20775
20776                if let Some(buffer) = edited_buffer {
20777                    if buffer.read(cx).file().is_none() {
20778                        cx.emit(EditorEvent::TitleChanged);
20779                    }
20780
20781                    if self.project.is_some() {
20782                        let buffer_id = buffer.read(cx).remote_id();
20783                        self.register_buffer(buffer_id, cx);
20784                        self.update_lsp_data(Some(buffer_id), window, cx);
20785                        self.refresh_inlay_hints(
20786                            InlayHintRefreshReason::BufferEdited(buffer_id),
20787                            cx,
20788                        );
20789                    }
20790                }
20791
20792                cx.emit(EditorEvent::BufferEdited);
20793                cx.emit(SearchEvent::MatchesInvalidated);
20794
20795                let Some(project) = &self.project else { return };
20796                let (telemetry, is_via_ssh) = {
20797                    let project = project.read(cx);
20798                    let telemetry = project.client().telemetry().clone();
20799                    let is_via_ssh = project.is_via_remote_server();
20800                    (telemetry, is_via_ssh)
20801                };
20802                telemetry.log_edit_event("editor", is_via_ssh);
20803            }
20804            multi_buffer::Event::ExcerptsAdded {
20805                buffer,
20806                predecessor,
20807                excerpts,
20808            } => {
20809                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20810                let buffer_id = buffer.read(cx).remote_id();
20811                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20812                    && let Some(project) = &self.project
20813                {
20814                    update_uncommitted_diff_for_buffer(
20815                        cx.entity(),
20816                        project,
20817                        [buffer.clone()],
20818                        self.buffer.clone(),
20819                        cx,
20820                    )
20821                    .detach();
20822                }
20823                self.update_lsp_data(Some(buffer_id), window, cx);
20824                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20825                cx.emit(EditorEvent::ExcerptsAdded {
20826                    buffer: buffer.clone(),
20827                    predecessor: *predecessor,
20828                    excerpts: excerpts.clone(),
20829                });
20830            }
20831            multi_buffer::Event::ExcerptsRemoved {
20832                ids,
20833                removed_buffer_ids,
20834            } => {
20835                if let Some(inlay_hints) = &mut self.inlay_hints {
20836                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
20837                }
20838                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20839                for buffer_id in removed_buffer_ids {
20840                    self.registered_buffers.remove(buffer_id);
20841                }
20842                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20843                cx.emit(EditorEvent::ExcerptsRemoved {
20844                    ids: ids.clone(),
20845                    removed_buffer_ids: removed_buffer_ids.clone(),
20846                });
20847            }
20848            multi_buffer::Event::ExcerptsEdited {
20849                excerpt_ids,
20850                buffer_ids,
20851            } => {
20852                self.display_map.update(cx, |map, cx| {
20853                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20854                });
20855                cx.emit(EditorEvent::ExcerptsEdited {
20856                    ids: excerpt_ids.clone(),
20857                });
20858            }
20859            multi_buffer::Event::ExcerptsExpanded { ids } => {
20860                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20861                self.refresh_document_highlights(cx);
20862                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20863            }
20864            multi_buffer::Event::Reparsed(buffer_id) => {
20865                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20866                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20867
20868                cx.emit(EditorEvent::Reparsed(*buffer_id));
20869            }
20870            multi_buffer::Event::DiffHunksToggled => {
20871                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20872            }
20873            multi_buffer::Event::LanguageChanged(buffer_id) => {
20874                self.registered_buffers.remove(&buffer_id);
20875                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20876                cx.emit(EditorEvent::Reparsed(*buffer_id));
20877                cx.notify();
20878            }
20879            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20880            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20881            multi_buffer::Event::FileHandleChanged
20882            | multi_buffer::Event::Reloaded
20883            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20884            multi_buffer::Event::DiagnosticsUpdated => {
20885                self.update_diagnostics_state(window, cx);
20886            }
20887            _ => {}
20888        };
20889    }
20890
20891    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20892        if !self.diagnostics_enabled() {
20893            return;
20894        }
20895        self.refresh_active_diagnostics(cx);
20896        self.refresh_inline_diagnostics(true, window, cx);
20897        self.scrollbar_marker_state.dirty = true;
20898        cx.notify();
20899    }
20900
20901    pub fn start_temporary_diff_override(&mut self) {
20902        self.load_diff_task.take();
20903        self.temporary_diff_override = true;
20904    }
20905
20906    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20907        self.temporary_diff_override = false;
20908        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20909        self.buffer.update(cx, |buffer, cx| {
20910            buffer.set_all_diff_hunks_collapsed(cx);
20911        });
20912
20913        if let Some(project) = self.project.clone() {
20914            self.load_diff_task = Some(
20915                update_uncommitted_diff_for_buffer(
20916                    cx.entity(),
20917                    &project,
20918                    self.buffer.read(cx).all_buffers(),
20919                    self.buffer.clone(),
20920                    cx,
20921                )
20922                .shared(),
20923            );
20924        }
20925    }
20926
20927    fn on_display_map_changed(
20928        &mut self,
20929        _: Entity<DisplayMap>,
20930        _: &mut Window,
20931        cx: &mut Context<Self>,
20932    ) {
20933        cx.notify();
20934    }
20935
20936    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20937        if self.diagnostics_enabled() {
20938            let new_severity = EditorSettings::get_global(cx)
20939                .diagnostics_max_severity
20940                .unwrap_or(DiagnosticSeverity::Hint);
20941            self.set_max_diagnostics_severity(new_severity, cx);
20942        }
20943        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20944        self.update_edit_prediction_settings(cx);
20945        self.refresh_edit_prediction(true, false, window, cx);
20946        self.refresh_inline_values(cx);
20947        self.refresh_inlay_hints(
20948            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20949                self.selections.newest_anchor().head(),
20950                &self.buffer.read(cx).snapshot(cx),
20951                cx,
20952            )),
20953            cx,
20954        );
20955
20956        let old_cursor_shape = self.cursor_shape;
20957        let old_show_breadcrumbs = self.show_breadcrumbs;
20958
20959        {
20960            let editor_settings = EditorSettings::get_global(cx);
20961            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20962            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20963            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20964            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20965        }
20966
20967        if old_cursor_shape != self.cursor_shape {
20968            cx.emit(EditorEvent::CursorShapeChanged);
20969        }
20970
20971        if old_show_breadcrumbs != self.show_breadcrumbs {
20972            cx.emit(EditorEvent::BreadcrumbsChanged);
20973        }
20974
20975        let project_settings = ProjectSettings::get_global(cx);
20976        self.serialize_dirty_buffers =
20977            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20978
20979        if self.mode.is_full() {
20980            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20981            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20982            if self.show_inline_diagnostics != show_inline_diagnostics {
20983                self.show_inline_diagnostics = show_inline_diagnostics;
20984                self.refresh_inline_diagnostics(false, window, cx);
20985            }
20986
20987            if self.git_blame_inline_enabled != inline_blame_enabled {
20988                self.toggle_git_blame_inline_internal(false, window, cx);
20989            }
20990
20991            let minimap_settings = EditorSettings::get_global(cx).minimap;
20992            if self.minimap_visibility != MinimapVisibility::Disabled {
20993                if self.minimap_visibility.settings_visibility()
20994                    != minimap_settings.minimap_enabled()
20995                {
20996                    self.set_minimap_visibility(
20997                        MinimapVisibility::for_mode(self.mode(), cx),
20998                        window,
20999                        cx,
21000                    );
21001                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21002                    minimap_entity.update(cx, |minimap_editor, cx| {
21003                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21004                    })
21005                }
21006            }
21007        }
21008
21009        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21010            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21011        }) {
21012            if !inlay_splice.is_empty() {
21013                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21014            }
21015            self.refresh_colors_for_visible_range(None, window, cx);
21016        }
21017
21018        cx.notify();
21019    }
21020
21021    pub fn set_searchable(&mut self, searchable: bool) {
21022        self.searchable = searchable;
21023    }
21024
21025    pub fn searchable(&self) -> bool {
21026        self.searchable
21027    }
21028
21029    pub fn open_excerpts_in_split(
21030        &mut self,
21031        _: &OpenExcerptsSplit,
21032        window: &mut Window,
21033        cx: &mut Context<Self>,
21034    ) {
21035        self.open_excerpts_common(None, true, window, cx)
21036    }
21037
21038    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21039        self.open_excerpts_common(None, false, window, cx)
21040    }
21041
21042    fn open_excerpts_common(
21043        &mut self,
21044        jump_data: Option<JumpData>,
21045        split: bool,
21046        window: &mut Window,
21047        cx: &mut Context<Self>,
21048    ) {
21049        let Some(workspace) = self.workspace() else {
21050            cx.propagate();
21051            return;
21052        };
21053
21054        if self.buffer.read(cx).is_singleton() {
21055            cx.propagate();
21056            return;
21057        }
21058
21059        let mut new_selections_by_buffer = HashMap::default();
21060        match &jump_data {
21061            Some(JumpData::MultiBufferPoint {
21062                excerpt_id,
21063                position,
21064                anchor,
21065                line_offset_from_top,
21066            }) => {
21067                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21068                if let Some(buffer) = multi_buffer_snapshot
21069                    .buffer_id_for_excerpt(*excerpt_id)
21070                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21071                {
21072                    let buffer_snapshot = buffer.read(cx).snapshot();
21073                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21074                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21075                    } else {
21076                        buffer_snapshot.clip_point(*position, Bias::Left)
21077                    };
21078                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21079                    new_selections_by_buffer.insert(
21080                        buffer,
21081                        (
21082                            vec![jump_to_offset..jump_to_offset],
21083                            Some(*line_offset_from_top),
21084                        ),
21085                    );
21086                }
21087            }
21088            Some(JumpData::MultiBufferRow {
21089                row,
21090                line_offset_from_top,
21091            }) => {
21092                let point = MultiBufferPoint::new(row.0, 0);
21093                if let Some((buffer, buffer_point, _)) =
21094                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21095                {
21096                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21097                    new_selections_by_buffer
21098                        .entry(buffer)
21099                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21100                        .0
21101                        .push(buffer_offset..buffer_offset)
21102                }
21103            }
21104            None => {
21105                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21106                let multi_buffer = self.buffer.read(cx);
21107                for selection in selections {
21108                    for (snapshot, range, _, anchor) in multi_buffer
21109                        .snapshot(cx)
21110                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21111                    {
21112                        if let Some(anchor) = anchor {
21113                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21114                            else {
21115                                continue;
21116                            };
21117                            let offset = text::ToOffset::to_offset(
21118                                &anchor.text_anchor,
21119                                &buffer_handle.read(cx).snapshot(),
21120                            );
21121                            let range = offset..offset;
21122                            new_selections_by_buffer
21123                                .entry(buffer_handle)
21124                                .or_insert((Vec::new(), None))
21125                                .0
21126                                .push(range)
21127                        } else {
21128                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21129                            else {
21130                                continue;
21131                            };
21132                            new_selections_by_buffer
21133                                .entry(buffer_handle)
21134                                .or_insert((Vec::new(), None))
21135                                .0
21136                                .push(range)
21137                        }
21138                    }
21139                }
21140            }
21141        }
21142
21143        new_selections_by_buffer
21144            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21145
21146        if new_selections_by_buffer.is_empty() {
21147            return;
21148        }
21149
21150        // We defer the pane interaction because we ourselves are a workspace item
21151        // and activating a new item causes the pane to call a method on us reentrantly,
21152        // which panics if we're on the stack.
21153        window.defer(cx, move |window, cx| {
21154            workspace.update(cx, |workspace, cx| {
21155                let pane = if split {
21156                    workspace.adjacent_pane(window, cx)
21157                } else {
21158                    workspace.active_pane().clone()
21159                };
21160
21161                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21162                    let editor = buffer
21163                        .read(cx)
21164                        .file()
21165                        .is_none()
21166                        .then(|| {
21167                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21168                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21169                            // Instead, we try to activate the existing editor in the pane first.
21170                            let (editor, pane_item_index) =
21171                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21172                                    let editor = item.downcast::<Editor>()?;
21173                                    let singleton_buffer =
21174                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21175                                    if singleton_buffer == buffer {
21176                                        Some((editor, i))
21177                                    } else {
21178                                        None
21179                                    }
21180                                })?;
21181                            pane.update(cx, |pane, cx| {
21182                                pane.activate_item(pane_item_index, true, true, window, cx)
21183                            });
21184                            Some(editor)
21185                        })
21186                        .flatten()
21187                        .unwrap_or_else(|| {
21188                            workspace.open_project_item::<Self>(
21189                                pane.clone(),
21190                                buffer,
21191                                true,
21192                                true,
21193                                window,
21194                                cx,
21195                            )
21196                        });
21197
21198                    editor.update(cx, |editor, cx| {
21199                        let autoscroll = match scroll_offset {
21200                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21201                            None => Autoscroll::newest(),
21202                        };
21203                        let nav_history = editor.nav_history.take();
21204                        editor.change_selections(
21205                            SelectionEffects::scroll(autoscroll),
21206                            window,
21207                            cx,
21208                            |s| {
21209                                s.select_ranges(ranges);
21210                            },
21211                        );
21212                        editor.nav_history = nav_history;
21213                    });
21214                }
21215            })
21216        });
21217    }
21218
21219    // For now, don't allow opening excerpts in buffers that aren't backed by
21220    // regular project files.
21221    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21222        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21223    }
21224
21225    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21226        let snapshot = self.buffer.read(cx).read(cx);
21227        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21228        Some(
21229            ranges
21230                .iter()
21231                .map(move |range| {
21232                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21233                })
21234                .collect(),
21235        )
21236    }
21237
21238    fn selection_replacement_ranges(
21239        &self,
21240        range: Range<OffsetUtf16>,
21241        cx: &mut App,
21242    ) -> Vec<Range<OffsetUtf16>> {
21243        let selections = self
21244            .selections
21245            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21246        let newest_selection = selections
21247            .iter()
21248            .max_by_key(|selection| selection.id)
21249            .unwrap();
21250        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21251        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21252        let snapshot = self.buffer.read(cx).read(cx);
21253        selections
21254            .into_iter()
21255            .map(|mut selection| {
21256                selection.start.0 =
21257                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21258                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21259                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21260                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21261            })
21262            .collect()
21263    }
21264
21265    fn report_editor_event(
21266        &self,
21267        reported_event: ReportEditorEvent,
21268        file_extension: Option<String>,
21269        cx: &App,
21270    ) {
21271        if cfg!(any(test, feature = "test-support")) {
21272            return;
21273        }
21274
21275        let Some(project) = &self.project else { return };
21276
21277        // If None, we are in a file without an extension
21278        let file = self
21279            .buffer
21280            .read(cx)
21281            .as_singleton()
21282            .and_then(|b| b.read(cx).file());
21283        let file_extension = file_extension.or(file
21284            .as_ref()
21285            .and_then(|file| Path::new(file.file_name(cx)).extension())
21286            .and_then(|e| e.to_str())
21287            .map(|a| a.to_string()));
21288
21289        let vim_mode = vim_enabled(cx);
21290
21291        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21292        let copilot_enabled = edit_predictions_provider
21293            == language::language_settings::EditPredictionProvider::Copilot;
21294        let copilot_enabled_for_language = self
21295            .buffer
21296            .read(cx)
21297            .language_settings(cx)
21298            .show_edit_predictions;
21299
21300        let project = project.read(cx);
21301        let event_type = reported_event.event_type();
21302
21303        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21304            telemetry::event!(
21305                event_type,
21306                type = if auto_saved {"autosave"} else {"manual"},
21307                file_extension,
21308                vim_mode,
21309                copilot_enabled,
21310                copilot_enabled_for_language,
21311                edit_predictions_provider,
21312                is_via_ssh = project.is_via_remote_server(),
21313            );
21314        } else {
21315            telemetry::event!(
21316                event_type,
21317                file_extension,
21318                vim_mode,
21319                copilot_enabled,
21320                copilot_enabled_for_language,
21321                edit_predictions_provider,
21322                is_via_ssh = project.is_via_remote_server(),
21323            );
21324        };
21325    }
21326
21327    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21328    /// with each line being an array of {text, highlight} objects.
21329    fn copy_highlight_json(
21330        &mut self,
21331        _: &CopyHighlightJson,
21332        window: &mut Window,
21333        cx: &mut Context<Self>,
21334    ) {
21335        #[derive(Serialize)]
21336        struct Chunk<'a> {
21337            text: String,
21338            highlight: Option<&'a str>,
21339        }
21340
21341        let snapshot = self.buffer.read(cx).snapshot(cx);
21342        let range = self
21343            .selected_text_range(false, window, cx)
21344            .and_then(|selection| {
21345                if selection.range.is_empty() {
21346                    None
21347                } else {
21348                    Some(
21349                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21350                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21351                    )
21352                }
21353            })
21354            .unwrap_or_else(|| 0..snapshot.len());
21355
21356        let chunks = snapshot.chunks(range, true);
21357        let mut lines = Vec::new();
21358        let mut line: VecDeque<Chunk> = VecDeque::new();
21359
21360        let Some(style) = self.style.as_ref() else {
21361            return;
21362        };
21363
21364        for chunk in chunks {
21365            let highlight = chunk
21366                .syntax_highlight_id
21367                .and_then(|id| id.name(&style.syntax));
21368            let mut chunk_lines = chunk.text.split('\n').peekable();
21369            while let Some(text) = chunk_lines.next() {
21370                let mut merged_with_last_token = false;
21371                if let Some(last_token) = line.back_mut()
21372                    && last_token.highlight == highlight
21373                {
21374                    last_token.text.push_str(text);
21375                    merged_with_last_token = true;
21376                }
21377
21378                if !merged_with_last_token {
21379                    line.push_back(Chunk {
21380                        text: text.into(),
21381                        highlight,
21382                    });
21383                }
21384
21385                if chunk_lines.peek().is_some() {
21386                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21387                        line.pop_front();
21388                    }
21389                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21390                        line.pop_back();
21391                    }
21392
21393                    lines.push(mem::take(&mut line));
21394                }
21395            }
21396        }
21397
21398        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21399            return;
21400        };
21401        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21402    }
21403
21404    pub fn open_context_menu(
21405        &mut self,
21406        _: &OpenContextMenu,
21407        window: &mut Window,
21408        cx: &mut Context<Self>,
21409    ) {
21410        self.request_autoscroll(Autoscroll::newest(), cx);
21411        let position = self
21412            .selections
21413            .newest_display(&self.display_snapshot(cx))
21414            .start;
21415        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21416    }
21417
21418    pub fn replay_insert_event(
21419        &mut self,
21420        text: &str,
21421        relative_utf16_range: Option<Range<isize>>,
21422        window: &mut Window,
21423        cx: &mut Context<Self>,
21424    ) {
21425        if !self.input_enabled {
21426            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21427            return;
21428        }
21429        if let Some(relative_utf16_range) = relative_utf16_range {
21430            let selections = self
21431                .selections
21432                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21433            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21434                let new_ranges = selections.into_iter().map(|range| {
21435                    let start = OffsetUtf16(
21436                        range
21437                            .head()
21438                            .0
21439                            .saturating_add_signed(relative_utf16_range.start),
21440                    );
21441                    let end = OffsetUtf16(
21442                        range
21443                            .head()
21444                            .0
21445                            .saturating_add_signed(relative_utf16_range.end),
21446                    );
21447                    start..end
21448                });
21449                s.select_ranges(new_ranges);
21450            });
21451        }
21452
21453        self.handle_input(text, window, cx);
21454    }
21455
21456    pub fn is_focused(&self, window: &Window) -> bool {
21457        self.focus_handle.is_focused(window)
21458    }
21459
21460    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21461        cx.emit(EditorEvent::Focused);
21462
21463        if let Some(descendant) = self
21464            .last_focused_descendant
21465            .take()
21466            .and_then(|descendant| descendant.upgrade())
21467        {
21468            window.focus(&descendant);
21469        } else {
21470            if let Some(blame) = self.blame.as_ref() {
21471                blame.update(cx, GitBlame::focus)
21472            }
21473
21474            self.blink_manager.update(cx, BlinkManager::enable);
21475            self.show_cursor_names(window, cx);
21476            self.buffer.update(cx, |buffer, cx| {
21477                buffer.finalize_last_transaction(cx);
21478                if self.leader_id.is_none() {
21479                    buffer.set_active_selections(
21480                        &self.selections.disjoint_anchors_arc(),
21481                        self.selections.line_mode(),
21482                        self.cursor_shape,
21483                        cx,
21484                    );
21485                }
21486            });
21487        }
21488    }
21489
21490    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21491        cx.emit(EditorEvent::FocusedIn)
21492    }
21493
21494    fn handle_focus_out(
21495        &mut self,
21496        event: FocusOutEvent,
21497        _window: &mut Window,
21498        cx: &mut Context<Self>,
21499    ) {
21500        if event.blurred != self.focus_handle {
21501            self.last_focused_descendant = Some(event.blurred);
21502        }
21503        self.selection_drag_state = SelectionDragState::None;
21504        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21505    }
21506
21507    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21508        self.blink_manager.update(cx, BlinkManager::disable);
21509        self.buffer
21510            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21511
21512        if let Some(blame) = self.blame.as_ref() {
21513            blame.update(cx, GitBlame::blur)
21514        }
21515        if !self.hover_state.focused(window, cx) {
21516            hide_hover(self, cx);
21517        }
21518        if !self
21519            .context_menu
21520            .borrow()
21521            .as_ref()
21522            .is_some_and(|context_menu| context_menu.focused(window, cx))
21523        {
21524            self.hide_context_menu(window, cx);
21525        }
21526        self.take_active_edit_prediction(cx);
21527        cx.emit(EditorEvent::Blurred);
21528        cx.notify();
21529    }
21530
21531    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21532        let mut pending: String = window
21533            .pending_input_keystrokes()
21534            .into_iter()
21535            .flatten()
21536            .filter_map(|keystroke| {
21537                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21538                    keystroke.key_char.clone()
21539                } else {
21540                    None
21541                }
21542            })
21543            .collect();
21544
21545        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21546            pending = "".to_string();
21547        }
21548
21549        let existing_pending = self
21550            .text_highlights::<PendingInput>(cx)
21551            .map(|(_, ranges)| ranges.to_vec());
21552        if existing_pending.is_none() && pending.is_empty() {
21553            return;
21554        }
21555        let transaction =
21556            self.transact(window, cx, |this, window, cx| {
21557                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21558                let edits = selections
21559                    .iter()
21560                    .map(|selection| (selection.end..selection.end, pending.clone()));
21561                this.edit(edits, cx);
21562                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21563                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21564                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21565                    }));
21566                });
21567                if let Some(existing_ranges) = existing_pending {
21568                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21569                    this.edit(edits, cx);
21570                }
21571            });
21572
21573        let snapshot = self.snapshot(window, cx);
21574        let ranges = self
21575            .selections
21576            .all::<usize>(&snapshot.display_snapshot)
21577            .into_iter()
21578            .map(|selection| {
21579                snapshot.buffer_snapshot().anchor_after(selection.end)
21580                    ..snapshot
21581                        .buffer_snapshot()
21582                        .anchor_before(selection.end + pending.len())
21583            })
21584            .collect();
21585
21586        if pending.is_empty() {
21587            self.clear_highlights::<PendingInput>(cx);
21588        } else {
21589            self.highlight_text::<PendingInput>(
21590                ranges,
21591                HighlightStyle {
21592                    underline: Some(UnderlineStyle {
21593                        thickness: px(1.),
21594                        color: None,
21595                        wavy: false,
21596                    }),
21597                    ..Default::default()
21598                },
21599                cx,
21600            );
21601        }
21602
21603        self.ime_transaction = self.ime_transaction.or(transaction);
21604        if let Some(transaction) = self.ime_transaction {
21605            self.buffer.update(cx, |buffer, cx| {
21606                buffer.group_until_transaction(transaction, cx);
21607            });
21608        }
21609
21610        if self.text_highlights::<PendingInput>(cx).is_none() {
21611            self.ime_transaction.take();
21612        }
21613    }
21614
21615    pub fn register_action_renderer(
21616        &mut self,
21617        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21618    ) -> Subscription {
21619        let id = self.next_editor_action_id.post_inc();
21620        self.editor_actions
21621            .borrow_mut()
21622            .insert(id, Box::new(listener));
21623
21624        let editor_actions = self.editor_actions.clone();
21625        Subscription::new(move || {
21626            editor_actions.borrow_mut().remove(&id);
21627        })
21628    }
21629
21630    pub fn register_action<A: Action>(
21631        &mut self,
21632        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21633    ) -> Subscription {
21634        let id = self.next_editor_action_id.post_inc();
21635        let listener = Arc::new(listener);
21636        self.editor_actions.borrow_mut().insert(
21637            id,
21638            Box::new(move |_, window, _| {
21639                let listener = listener.clone();
21640                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21641                    let action = action.downcast_ref().unwrap();
21642                    if phase == DispatchPhase::Bubble {
21643                        listener(action, window, cx)
21644                    }
21645                })
21646            }),
21647        );
21648
21649        let editor_actions = self.editor_actions.clone();
21650        Subscription::new(move || {
21651            editor_actions.borrow_mut().remove(&id);
21652        })
21653    }
21654
21655    pub fn file_header_size(&self) -> u32 {
21656        FILE_HEADER_HEIGHT
21657    }
21658
21659    pub fn restore(
21660        &mut self,
21661        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21662        window: &mut Window,
21663        cx: &mut Context<Self>,
21664    ) {
21665        let workspace = self.workspace();
21666        let project = self.project();
21667        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21668            let mut tasks = Vec::new();
21669            for (buffer_id, changes) in revert_changes {
21670                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21671                    buffer.update(cx, |buffer, cx| {
21672                        buffer.edit(
21673                            changes
21674                                .into_iter()
21675                                .map(|(range, text)| (range, text.to_string())),
21676                            None,
21677                            cx,
21678                        );
21679                    });
21680
21681                    if let Some(project) =
21682                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21683                    {
21684                        project.update(cx, |project, cx| {
21685                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21686                        })
21687                    }
21688                }
21689            }
21690            tasks
21691        });
21692        cx.spawn_in(window, async move |_, cx| {
21693            for (buffer, task) in save_tasks {
21694                let result = task.await;
21695                if result.is_err() {
21696                    let Some(path) = buffer
21697                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21698                        .ok()
21699                    else {
21700                        continue;
21701                    };
21702                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21703                        let Some(task) = cx
21704                            .update_window_entity(workspace, |workspace, window, cx| {
21705                                workspace
21706                                    .open_path_preview(path, None, false, false, false, window, cx)
21707                            })
21708                            .ok()
21709                        else {
21710                            continue;
21711                        };
21712                        task.await.log_err();
21713                    }
21714                }
21715            }
21716        })
21717        .detach();
21718        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21719            selections.refresh()
21720        });
21721    }
21722
21723    pub fn to_pixel_point(
21724        &self,
21725        source: multi_buffer::Anchor,
21726        editor_snapshot: &EditorSnapshot,
21727        window: &mut Window,
21728    ) -> Option<gpui::Point<Pixels>> {
21729        let source_point = source.to_display_point(editor_snapshot);
21730        self.display_to_pixel_point(source_point, editor_snapshot, window)
21731    }
21732
21733    pub fn display_to_pixel_point(
21734        &self,
21735        source: DisplayPoint,
21736        editor_snapshot: &EditorSnapshot,
21737        window: &mut Window,
21738    ) -> Option<gpui::Point<Pixels>> {
21739        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21740        let text_layout_details = self.text_layout_details(window);
21741        let scroll_top = text_layout_details
21742            .scroll_anchor
21743            .scroll_position(editor_snapshot)
21744            .y;
21745
21746        if source.row().as_f64() < scroll_top.floor() {
21747            return None;
21748        }
21749        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21750        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21751        Some(gpui::Point::new(source_x, source_y))
21752    }
21753
21754    pub fn has_visible_completions_menu(&self) -> bool {
21755        !self.edit_prediction_preview_is_active()
21756            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21757                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21758            })
21759    }
21760
21761    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21762        if self.mode.is_minimap() {
21763            return;
21764        }
21765        self.addons
21766            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21767    }
21768
21769    pub fn unregister_addon<T: Addon>(&mut self) {
21770        self.addons.remove(&std::any::TypeId::of::<T>());
21771    }
21772
21773    pub fn addon<T: Addon>(&self) -> Option<&T> {
21774        let type_id = std::any::TypeId::of::<T>();
21775        self.addons
21776            .get(&type_id)
21777            .and_then(|item| item.to_any().downcast_ref::<T>())
21778    }
21779
21780    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21781        let type_id = std::any::TypeId::of::<T>();
21782        self.addons
21783            .get_mut(&type_id)
21784            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21785    }
21786
21787    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21788        let text_layout_details = self.text_layout_details(window);
21789        let style = &text_layout_details.editor_style;
21790        let font_id = window.text_system().resolve_font(&style.text.font());
21791        let font_size = style.text.font_size.to_pixels(window.rem_size());
21792        let line_height = style.text.line_height_in_pixels(window.rem_size());
21793        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21794        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21795
21796        CharacterDimensions {
21797            em_width,
21798            em_advance,
21799            line_height,
21800        }
21801    }
21802
21803    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21804        self.load_diff_task.clone()
21805    }
21806
21807    fn read_metadata_from_db(
21808        &mut self,
21809        item_id: u64,
21810        workspace_id: WorkspaceId,
21811        window: &mut Window,
21812        cx: &mut Context<Editor>,
21813    ) {
21814        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21815            && !self.mode.is_minimap()
21816            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21817        {
21818            let buffer_snapshot = OnceCell::new();
21819
21820            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21821                && !folds.is_empty()
21822            {
21823                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21824                self.fold_ranges(
21825                    folds
21826                        .into_iter()
21827                        .map(|(start, end)| {
21828                            snapshot.clip_offset(start, Bias::Left)
21829                                ..snapshot.clip_offset(end, Bias::Right)
21830                        })
21831                        .collect(),
21832                    false,
21833                    window,
21834                    cx,
21835                );
21836            }
21837
21838            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21839                && !selections.is_empty()
21840            {
21841                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21842                // skip adding the initial selection to selection history
21843                self.selection_history.mode = SelectionHistoryMode::Skipping;
21844                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21845                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21846                        snapshot.clip_offset(start, Bias::Left)
21847                            ..snapshot.clip_offset(end, Bias::Right)
21848                    }));
21849                });
21850                self.selection_history.mode = SelectionHistoryMode::Normal;
21851            };
21852        }
21853
21854        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21855    }
21856
21857    fn update_lsp_data(
21858        &mut self,
21859        for_buffer: Option<BufferId>,
21860        window: &mut Window,
21861        cx: &mut Context<'_, Self>,
21862    ) {
21863        self.pull_diagnostics(for_buffer, window, cx);
21864        self.refresh_colors_for_visible_range(for_buffer, window, cx);
21865    }
21866
21867    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
21868        if self.ignore_lsp_data() {
21869            return;
21870        }
21871        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
21872            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
21873        }
21874    }
21875
21876    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
21877        if !self.registered_buffers.contains_key(&buffer_id)
21878            && let Some(project) = self.project.as_ref()
21879        {
21880            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
21881                project.update(cx, |project, cx| {
21882                    self.registered_buffers.insert(
21883                        buffer_id,
21884                        project.register_buffer_with_language_servers(&buffer, cx),
21885                    );
21886                });
21887            } else {
21888                self.registered_buffers.remove(&buffer_id);
21889            }
21890        }
21891    }
21892
21893    fn ignore_lsp_data(&self) -> bool {
21894        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
21895        // skip any LSP updates for it.
21896        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
21897    }
21898}
21899
21900fn edit_for_markdown_paste<'a>(
21901    buffer: &MultiBufferSnapshot,
21902    range: Range<usize>,
21903    to_insert: &'a str,
21904    url: Option<url::Url>,
21905) -> (Range<usize>, Cow<'a, str>) {
21906    if url.is_none() {
21907        return (range, Cow::Borrowed(to_insert));
21908    };
21909
21910    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21911
21912    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21913        Cow::Borrowed(to_insert)
21914    } else {
21915        Cow::Owned(format!("[{old_text}]({to_insert})"))
21916    };
21917    (range, new_text)
21918}
21919
21920fn vim_enabled(cx: &App) -> bool {
21921    vim_mode_setting::VimModeSetting::try_get(cx)
21922        .map(|vim_mode| vim_mode.0)
21923        .unwrap_or(false)
21924}
21925
21926fn process_completion_for_edit(
21927    completion: &Completion,
21928    intent: CompletionIntent,
21929    buffer: &Entity<Buffer>,
21930    cursor_position: &text::Anchor,
21931    cx: &mut Context<Editor>,
21932) -> CompletionEdit {
21933    let buffer = buffer.read(cx);
21934    let buffer_snapshot = buffer.snapshot();
21935    let (snippet, new_text) = if completion.is_snippet() {
21936        let mut snippet_source = completion.new_text.clone();
21937        // Workaround for typescript language server issues so that methods don't expand within
21938        // strings and functions with type expressions. The previous point is used because the query
21939        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21940        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
21941        let previous_point = if previous_point.column > 0 {
21942            cursor_position.to_previous_offset(&buffer_snapshot)
21943        } else {
21944            cursor_position.to_offset(&buffer_snapshot)
21945        };
21946        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21947            && scope.prefers_label_for_snippet_in_completion()
21948            && let Some(label) = completion.label()
21949            && matches!(
21950                completion.kind(),
21951                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21952            )
21953        {
21954            snippet_source = label;
21955        }
21956        match Snippet::parse(&snippet_source).log_err() {
21957            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21958            None => (None, completion.new_text.clone()),
21959        }
21960    } else {
21961        (None, completion.new_text.clone())
21962    };
21963
21964    let mut range_to_replace = {
21965        let replace_range = &completion.replace_range;
21966        if let CompletionSource::Lsp {
21967            insert_range: Some(insert_range),
21968            ..
21969        } = &completion.source
21970        {
21971            debug_assert_eq!(
21972                insert_range.start, replace_range.start,
21973                "insert_range and replace_range should start at the same position"
21974            );
21975            debug_assert!(
21976                insert_range
21977                    .start
21978                    .cmp(cursor_position, &buffer_snapshot)
21979                    .is_le(),
21980                "insert_range should start before or at cursor position"
21981            );
21982            debug_assert!(
21983                replace_range
21984                    .start
21985                    .cmp(cursor_position, &buffer_snapshot)
21986                    .is_le(),
21987                "replace_range should start before or at cursor position"
21988            );
21989
21990            let should_replace = match intent {
21991                CompletionIntent::CompleteWithInsert => false,
21992                CompletionIntent::CompleteWithReplace => true,
21993                CompletionIntent::Complete | CompletionIntent::Compose => {
21994                    let insert_mode =
21995                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21996                            .completions
21997                            .lsp_insert_mode;
21998                    match insert_mode {
21999                        LspInsertMode::Insert => false,
22000                        LspInsertMode::Replace => true,
22001                        LspInsertMode::ReplaceSubsequence => {
22002                            let mut text_to_replace = buffer.chars_for_range(
22003                                buffer.anchor_before(replace_range.start)
22004                                    ..buffer.anchor_after(replace_range.end),
22005                            );
22006                            let mut current_needle = text_to_replace.next();
22007                            for haystack_ch in completion.label.text.chars() {
22008                                if let Some(needle_ch) = current_needle
22009                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22010                                {
22011                                    current_needle = text_to_replace.next();
22012                                }
22013                            }
22014                            current_needle.is_none()
22015                        }
22016                        LspInsertMode::ReplaceSuffix => {
22017                            if replace_range
22018                                .end
22019                                .cmp(cursor_position, &buffer_snapshot)
22020                                .is_gt()
22021                            {
22022                                let range_after_cursor = *cursor_position..replace_range.end;
22023                                let text_after_cursor = buffer
22024                                    .text_for_range(
22025                                        buffer.anchor_before(range_after_cursor.start)
22026                                            ..buffer.anchor_after(range_after_cursor.end),
22027                                    )
22028                                    .collect::<String>()
22029                                    .to_ascii_lowercase();
22030                                completion
22031                                    .label
22032                                    .text
22033                                    .to_ascii_lowercase()
22034                                    .ends_with(&text_after_cursor)
22035                            } else {
22036                                true
22037                            }
22038                        }
22039                    }
22040                }
22041            };
22042
22043            if should_replace {
22044                replace_range.clone()
22045            } else {
22046                insert_range.clone()
22047            }
22048        } else {
22049            replace_range.clone()
22050        }
22051    };
22052
22053    if range_to_replace
22054        .end
22055        .cmp(cursor_position, &buffer_snapshot)
22056        .is_lt()
22057    {
22058        range_to_replace.end = *cursor_position;
22059    }
22060
22061    CompletionEdit {
22062        new_text,
22063        replace_range: range_to_replace.to_offset(buffer),
22064        snippet,
22065    }
22066}
22067
22068struct CompletionEdit {
22069    new_text: String,
22070    replace_range: Range<usize>,
22071    snippet: Option<Snippet>,
22072}
22073
22074fn insert_extra_newline_brackets(
22075    buffer: &MultiBufferSnapshot,
22076    range: Range<usize>,
22077    language: &language::LanguageScope,
22078) -> bool {
22079    let leading_whitespace_len = buffer
22080        .reversed_chars_at(range.start)
22081        .take_while(|c| c.is_whitespace() && *c != '\n')
22082        .map(|c| c.len_utf8())
22083        .sum::<usize>();
22084    let trailing_whitespace_len = buffer
22085        .chars_at(range.end)
22086        .take_while(|c| c.is_whitespace() && *c != '\n')
22087        .map(|c| c.len_utf8())
22088        .sum::<usize>();
22089    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22090
22091    language.brackets().any(|(pair, enabled)| {
22092        let pair_start = pair.start.trim_end();
22093        let pair_end = pair.end.trim_start();
22094
22095        enabled
22096            && pair.newline
22097            && buffer.contains_str_at(range.end, pair_end)
22098            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22099    })
22100}
22101
22102fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22103    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22104        [(buffer, range, _)] => (*buffer, range.clone()),
22105        _ => return false,
22106    };
22107    let pair = {
22108        let mut result: Option<BracketMatch> = None;
22109
22110        for pair in buffer
22111            .all_bracket_ranges(range.clone())
22112            .filter(move |pair| {
22113                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22114            })
22115        {
22116            let len = pair.close_range.end - pair.open_range.start;
22117
22118            if let Some(existing) = &result {
22119                let existing_len = existing.close_range.end - existing.open_range.start;
22120                if len > existing_len {
22121                    continue;
22122                }
22123            }
22124
22125            result = Some(pair);
22126        }
22127
22128        result
22129    };
22130    let Some(pair) = pair else {
22131        return false;
22132    };
22133    pair.newline_only
22134        && buffer
22135            .chars_for_range(pair.open_range.end..range.start)
22136            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22137            .all(|c| c.is_whitespace() && c != '\n')
22138}
22139
22140fn update_uncommitted_diff_for_buffer(
22141    editor: Entity<Editor>,
22142    project: &Entity<Project>,
22143    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22144    buffer: Entity<MultiBuffer>,
22145    cx: &mut App,
22146) -> Task<()> {
22147    let mut tasks = Vec::new();
22148    project.update(cx, |project, cx| {
22149        for buffer in buffers {
22150            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22151                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22152            }
22153        }
22154    });
22155    cx.spawn(async move |cx| {
22156        let diffs = future::join_all(tasks).await;
22157        if editor
22158            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22159            .unwrap_or(false)
22160        {
22161            return;
22162        }
22163
22164        buffer
22165            .update(cx, |buffer, cx| {
22166                for diff in diffs.into_iter().flatten() {
22167                    buffer.add_diff(diff, cx);
22168                }
22169            })
22170            .ok();
22171    })
22172}
22173
22174fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22175    let tab_size = tab_size.get() as usize;
22176    let mut width = offset;
22177
22178    for ch in text.chars() {
22179        width += if ch == '\t' {
22180            tab_size - (width % tab_size)
22181        } else {
22182            1
22183        };
22184    }
22185
22186    width - offset
22187}
22188
22189#[cfg(test)]
22190mod tests {
22191    use super::*;
22192
22193    #[test]
22194    fn test_string_size_with_expanded_tabs() {
22195        let nz = |val| NonZeroU32::new(val).unwrap();
22196        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22197        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22198        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22199        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22200        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22201        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22202        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22203        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22204    }
22205}
22206
22207/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22208struct WordBreakingTokenizer<'a> {
22209    input: &'a str,
22210}
22211
22212impl<'a> WordBreakingTokenizer<'a> {
22213    fn new(input: &'a str) -> Self {
22214        Self { input }
22215    }
22216}
22217
22218fn is_char_ideographic(ch: char) -> bool {
22219    use unicode_script::Script::*;
22220    use unicode_script::UnicodeScript;
22221    matches!(ch.script(), Han | Tangut | Yi)
22222}
22223
22224fn is_grapheme_ideographic(text: &str) -> bool {
22225    text.chars().any(is_char_ideographic)
22226}
22227
22228fn is_grapheme_whitespace(text: &str) -> bool {
22229    text.chars().any(|x| x.is_whitespace())
22230}
22231
22232fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22233    text.chars()
22234        .next()
22235        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22236}
22237
22238#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22239enum WordBreakToken<'a> {
22240    Word { token: &'a str, grapheme_len: usize },
22241    InlineWhitespace { token: &'a str, grapheme_len: usize },
22242    Newline,
22243}
22244
22245impl<'a> Iterator for WordBreakingTokenizer<'a> {
22246    /// Yields a span, the count of graphemes in the token, and whether it was
22247    /// whitespace. Note that it also breaks at word boundaries.
22248    type Item = WordBreakToken<'a>;
22249
22250    fn next(&mut self) -> Option<Self::Item> {
22251        use unicode_segmentation::UnicodeSegmentation;
22252        if self.input.is_empty() {
22253            return None;
22254        }
22255
22256        let mut iter = self.input.graphemes(true).peekable();
22257        let mut offset = 0;
22258        let mut grapheme_len = 0;
22259        if let Some(first_grapheme) = iter.next() {
22260            let is_newline = first_grapheme == "\n";
22261            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22262            offset += first_grapheme.len();
22263            grapheme_len += 1;
22264            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22265                if let Some(grapheme) = iter.peek().copied()
22266                    && should_stay_with_preceding_ideograph(grapheme)
22267                {
22268                    offset += grapheme.len();
22269                    grapheme_len += 1;
22270                }
22271            } else {
22272                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22273                let mut next_word_bound = words.peek().copied();
22274                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22275                    next_word_bound = words.next();
22276                }
22277                while let Some(grapheme) = iter.peek().copied() {
22278                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22279                        break;
22280                    };
22281                    if is_grapheme_whitespace(grapheme) != is_whitespace
22282                        || (grapheme == "\n") != is_newline
22283                    {
22284                        break;
22285                    };
22286                    offset += grapheme.len();
22287                    grapheme_len += 1;
22288                    iter.next();
22289                }
22290            }
22291            let token = &self.input[..offset];
22292            self.input = &self.input[offset..];
22293            if token == "\n" {
22294                Some(WordBreakToken::Newline)
22295            } else if is_whitespace {
22296                Some(WordBreakToken::InlineWhitespace {
22297                    token,
22298                    grapheme_len,
22299                })
22300            } else {
22301                Some(WordBreakToken::Word {
22302                    token,
22303                    grapheme_len,
22304                })
22305            }
22306        } else {
22307            None
22308        }
22309    }
22310}
22311
22312#[test]
22313fn test_word_breaking_tokenizer() {
22314    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22315        ("", &[]),
22316        ("  ", &[whitespace("  ", 2)]),
22317        ("Ʒ", &[word("Ʒ", 1)]),
22318        ("Ǽ", &[word("Ǽ", 1)]),
22319        ("", &[word("", 1)]),
22320        ("⋑⋑", &[word("⋑⋑", 2)]),
22321        (
22322            "原理,进而",
22323            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22324        ),
22325        (
22326            "hello world",
22327            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22328        ),
22329        (
22330            "hello, world",
22331            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22332        ),
22333        (
22334            "  hello world",
22335            &[
22336                whitespace("  ", 2),
22337                word("hello", 5),
22338                whitespace(" ", 1),
22339                word("world", 5),
22340            ],
22341        ),
22342        (
22343            "这是什么 \n 钢笔",
22344            &[
22345                word("", 1),
22346                word("", 1),
22347                word("", 1),
22348                word("", 1),
22349                whitespace(" ", 1),
22350                newline(),
22351                whitespace(" ", 1),
22352                word("", 1),
22353                word("", 1),
22354            ],
22355        ),
22356        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22357    ];
22358
22359    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22360        WordBreakToken::Word {
22361            token,
22362            grapheme_len,
22363        }
22364    }
22365
22366    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22367        WordBreakToken::InlineWhitespace {
22368            token,
22369            grapheme_len,
22370        }
22371    }
22372
22373    fn newline() -> WordBreakToken<'static> {
22374        WordBreakToken::Newline
22375    }
22376
22377    for (input, result) in tests {
22378        assert_eq!(
22379            WordBreakingTokenizer::new(input)
22380                .collect::<Vec<_>>()
22381                .as_slice(),
22382            *result,
22383        );
22384    }
22385}
22386
22387fn wrap_with_prefix(
22388    first_line_prefix: String,
22389    subsequent_lines_prefix: String,
22390    unwrapped_text: String,
22391    wrap_column: usize,
22392    tab_size: NonZeroU32,
22393    preserve_existing_whitespace: bool,
22394) -> String {
22395    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22396    let subsequent_lines_prefix_len =
22397        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22398    let mut wrapped_text = String::new();
22399    let mut current_line = first_line_prefix;
22400    let mut is_first_line = true;
22401
22402    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22403    let mut current_line_len = first_line_prefix_len;
22404    let mut in_whitespace = false;
22405    for token in tokenizer {
22406        let have_preceding_whitespace = in_whitespace;
22407        match token {
22408            WordBreakToken::Word {
22409                token,
22410                grapheme_len,
22411            } => {
22412                in_whitespace = false;
22413                let current_prefix_len = if is_first_line {
22414                    first_line_prefix_len
22415                } else {
22416                    subsequent_lines_prefix_len
22417                };
22418                if current_line_len + grapheme_len > wrap_column
22419                    && current_line_len != current_prefix_len
22420                {
22421                    wrapped_text.push_str(current_line.trim_end());
22422                    wrapped_text.push('\n');
22423                    is_first_line = false;
22424                    current_line = subsequent_lines_prefix.clone();
22425                    current_line_len = subsequent_lines_prefix_len;
22426                }
22427                current_line.push_str(token);
22428                current_line_len += grapheme_len;
22429            }
22430            WordBreakToken::InlineWhitespace {
22431                mut token,
22432                mut grapheme_len,
22433            } => {
22434                in_whitespace = true;
22435                if have_preceding_whitespace && !preserve_existing_whitespace {
22436                    continue;
22437                }
22438                if !preserve_existing_whitespace {
22439                    // Keep a single whitespace grapheme as-is
22440                    if let Some(first) =
22441                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22442                    {
22443                        token = first;
22444                    } else {
22445                        token = " ";
22446                    }
22447                    grapheme_len = 1;
22448                }
22449                let current_prefix_len = if is_first_line {
22450                    first_line_prefix_len
22451                } else {
22452                    subsequent_lines_prefix_len
22453                };
22454                if current_line_len + grapheme_len > wrap_column {
22455                    wrapped_text.push_str(current_line.trim_end());
22456                    wrapped_text.push('\n');
22457                    is_first_line = false;
22458                    current_line = subsequent_lines_prefix.clone();
22459                    current_line_len = subsequent_lines_prefix_len;
22460                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22461                    current_line.push_str(token);
22462                    current_line_len += grapheme_len;
22463                }
22464            }
22465            WordBreakToken::Newline => {
22466                in_whitespace = true;
22467                let current_prefix_len = if is_first_line {
22468                    first_line_prefix_len
22469                } else {
22470                    subsequent_lines_prefix_len
22471                };
22472                if preserve_existing_whitespace {
22473                    wrapped_text.push_str(current_line.trim_end());
22474                    wrapped_text.push('\n');
22475                    is_first_line = false;
22476                    current_line = subsequent_lines_prefix.clone();
22477                    current_line_len = subsequent_lines_prefix_len;
22478                } else if have_preceding_whitespace {
22479                    continue;
22480                } else if current_line_len + 1 > wrap_column
22481                    && current_line_len != current_prefix_len
22482                {
22483                    wrapped_text.push_str(current_line.trim_end());
22484                    wrapped_text.push('\n');
22485                    is_first_line = false;
22486                    current_line = subsequent_lines_prefix.clone();
22487                    current_line_len = subsequent_lines_prefix_len;
22488                } else if current_line_len != current_prefix_len {
22489                    current_line.push(' ');
22490                    current_line_len += 1;
22491                }
22492            }
22493        }
22494    }
22495
22496    if !current_line.is_empty() {
22497        wrapped_text.push_str(&current_line);
22498    }
22499    wrapped_text
22500}
22501
22502#[test]
22503fn test_wrap_with_prefix() {
22504    assert_eq!(
22505        wrap_with_prefix(
22506            "# ".to_string(),
22507            "# ".to_string(),
22508            "abcdefg".to_string(),
22509            4,
22510            NonZeroU32::new(4).unwrap(),
22511            false,
22512        ),
22513        "# abcdefg"
22514    );
22515    assert_eq!(
22516        wrap_with_prefix(
22517            "".to_string(),
22518            "".to_string(),
22519            "\thello world".to_string(),
22520            8,
22521            NonZeroU32::new(4).unwrap(),
22522            false,
22523        ),
22524        "hello\nworld"
22525    );
22526    assert_eq!(
22527        wrap_with_prefix(
22528            "// ".to_string(),
22529            "// ".to_string(),
22530            "xx \nyy zz aa bb cc".to_string(),
22531            12,
22532            NonZeroU32::new(4).unwrap(),
22533            false,
22534        ),
22535        "// xx yy zz\n// aa bb cc"
22536    );
22537    assert_eq!(
22538        wrap_with_prefix(
22539            String::new(),
22540            String::new(),
22541            "这是什么 \n 钢笔".to_string(),
22542            3,
22543            NonZeroU32::new(4).unwrap(),
22544            false,
22545        ),
22546        "这是什\n么 钢\n"
22547    );
22548    assert_eq!(
22549        wrap_with_prefix(
22550            String::new(),
22551            String::new(),
22552            format!("foo{}bar", '\u{2009}'), // thin space
22553            80,
22554            NonZeroU32::new(4).unwrap(),
22555            false,
22556        ),
22557        format!("foo{}bar", '\u{2009}')
22558    );
22559}
22560
22561pub trait CollaborationHub {
22562    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22563    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22564    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22565}
22566
22567impl CollaborationHub for Entity<Project> {
22568    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22569        self.read(cx).collaborators()
22570    }
22571
22572    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22573        self.read(cx).user_store().read(cx).participant_indices()
22574    }
22575
22576    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22577        let this = self.read(cx);
22578        let user_ids = this.collaborators().values().map(|c| c.user_id);
22579        this.user_store().read(cx).participant_names(user_ids, cx)
22580    }
22581}
22582
22583pub trait SemanticsProvider {
22584    fn hover(
22585        &self,
22586        buffer: &Entity<Buffer>,
22587        position: text::Anchor,
22588        cx: &mut App,
22589    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22590
22591    fn inline_values(
22592        &self,
22593        buffer_handle: Entity<Buffer>,
22594        range: Range<text::Anchor>,
22595        cx: &mut App,
22596    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22597
22598    fn applicable_inlay_chunks(
22599        &self,
22600        buffer: &Entity<Buffer>,
22601        ranges: &[Range<text::Anchor>],
22602        cx: &mut App,
22603    ) -> Vec<Range<BufferRow>>;
22604
22605    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22606
22607    fn inlay_hints(
22608        &self,
22609        invalidate: InvalidationStrategy,
22610        buffer: Entity<Buffer>,
22611        ranges: Vec<Range<text::Anchor>>,
22612        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22613        cx: &mut App,
22614    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22615
22616    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22617
22618    fn document_highlights(
22619        &self,
22620        buffer: &Entity<Buffer>,
22621        position: text::Anchor,
22622        cx: &mut App,
22623    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22624
22625    fn definitions(
22626        &self,
22627        buffer: &Entity<Buffer>,
22628        position: text::Anchor,
22629        kind: GotoDefinitionKind,
22630        cx: &mut App,
22631    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22632
22633    fn range_for_rename(
22634        &self,
22635        buffer: &Entity<Buffer>,
22636        position: text::Anchor,
22637        cx: &mut App,
22638    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22639
22640    fn perform_rename(
22641        &self,
22642        buffer: &Entity<Buffer>,
22643        position: text::Anchor,
22644        new_name: String,
22645        cx: &mut App,
22646    ) -> Option<Task<Result<ProjectTransaction>>>;
22647}
22648
22649pub trait CompletionProvider {
22650    fn completions(
22651        &self,
22652        excerpt_id: ExcerptId,
22653        buffer: &Entity<Buffer>,
22654        buffer_position: text::Anchor,
22655        trigger: CompletionContext,
22656        window: &mut Window,
22657        cx: &mut Context<Editor>,
22658    ) -> Task<Result<Vec<CompletionResponse>>>;
22659
22660    fn resolve_completions(
22661        &self,
22662        _buffer: Entity<Buffer>,
22663        _completion_indices: Vec<usize>,
22664        _completions: Rc<RefCell<Box<[Completion]>>>,
22665        _cx: &mut Context<Editor>,
22666    ) -> Task<Result<bool>> {
22667        Task::ready(Ok(false))
22668    }
22669
22670    fn apply_additional_edits_for_completion(
22671        &self,
22672        _buffer: Entity<Buffer>,
22673        _completions: Rc<RefCell<Box<[Completion]>>>,
22674        _completion_index: usize,
22675        _push_to_history: bool,
22676        _cx: &mut Context<Editor>,
22677    ) -> Task<Result<Option<language::Transaction>>> {
22678        Task::ready(Ok(None))
22679    }
22680
22681    fn is_completion_trigger(
22682        &self,
22683        buffer: &Entity<Buffer>,
22684        position: language::Anchor,
22685        text: &str,
22686        trigger_in_words: bool,
22687        menu_is_open: bool,
22688        cx: &mut Context<Editor>,
22689    ) -> bool;
22690
22691    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22692
22693    fn sort_completions(&self) -> bool {
22694        true
22695    }
22696
22697    fn filter_completions(&self) -> bool {
22698        true
22699    }
22700}
22701
22702pub trait CodeActionProvider {
22703    fn id(&self) -> Arc<str>;
22704
22705    fn code_actions(
22706        &self,
22707        buffer: &Entity<Buffer>,
22708        range: Range<text::Anchor>,
22709        window: &mut Window,
22710        cx: &mut App,
22711    ) -> Task<Result<Vec<CodeAction>>>;
22712
22713    fn apply_code_action(
22714        &self,
22715        buffer_handle: Entity<Buffer>,
22716        action: CodeAction,
22717        excerpt_id: ExcerptId,
22718        push_to_history: bool,
22719        window: &mut Window,
22720        cx: &mut App,
22721    ) -> Task<Result<ProjectTransaction>>;
22722}
22723
22724impl CodeActionProvider for Entity<Project> {
22725    fn id(&self) -> Arc<str> {
22726        "project".into()
22727    }
22728
22729    fn code_actions(
22730        &self,
22731        buffer: &Entity<Buffer>,
22732        range: Range<text::Anchor>,
22733        _window: &mut Window,
22734        cx: &mut App,
22735    ) -> Task<Result<Vec<CodeAction>>> {
22736        self.update(cx, |project, cx| {
22737            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22738            let code_actions = project.code_actions(buffer, range, None, cx);
22739            cx.background_spawn(async move {
22740                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22741                Ok(code_lens_actions
22742                    .context("code lens fetch")?
22743                    .into_iter()
22744                    .flatten()
22745                    .chain(
22746                        code_actions
22747                            .context("code action fetch")?
22748                            .into_iter()
22749                            .flatten(),
22750                    )
22751                    .collect())
22752            })
22753        })
22754    }
22755
22756    fn apply_code_action(
22757        &self,
22758        buffer_handle: Entity<Buffer>,
22759        action: CodeAction,
22760        _excerpt_id: ExcerptId,
22761        push_to_history: bool,
22762        _window: &mut Window,
22763        cx: &mut App,
22764    ) -> Task<Result<ProjectTransaction>> {
22765        self.update(cx, |project, cx| {
22766            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22767        })
22768    }
22769}
22770
22771fn snippet_completions(
22772    project: &Project,
22773    buffer: &Entity<Buffer>,
22774    buffer_position: text::Anchor,
22775    cx: &mut App,
22776) -> Task<Result<CompletionResponse>> {
22777    let languages = buffer.read(cx).languages_at(buffer_position);
22778    let snippet_store = project.snippets().read(cx);
22779
22780    let scopes: Vec<_> = languages
22781        .iter()
22782        .filter_map(|language| {
22783            let language_name = language.lsp_id();
22784            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22785
22786            if snippets.is_empty() {
22787                None
22788            } else {
22789                Some((language.default_scope(), snippets))
22790            }
22791        })
22792        .collect();
22793
22794    if scopes.is_empty() {
22795        return Task::ready(Ok(CompletionResponse {
22796            completions: vec![],
22797            display_options: CompletionDisplayOptions::default(),
22798            is_incomplete: false,
22799        }));
22800    }
22801
22802    let snapshot = buffer.read(cx).text_snapshot();
22803    let executor = cx.background_executor().clone();
22804
22805    cx.background_spawn(async move {
22806        let mut is_incomplete = false;
22807        let mut completions: Vec<Completion> = Vec::new();
22808        for (scope, snippets) in scopes.into_iter() {
22809            let classifier =
22810                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22811
22812            const MAX_WORD_PREFIX_LEN: usize = 128;
22813            let last_word: String = snapshot
22814                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22815                .take(MAX_WORD_PREFIX_LEN)
22816                .take_while(|c| classifier.is_word(*c))
22817                .collect::<String>()
22818                .chars()
22819                .rev()
22820                .collect();
22821
22822            if last_word.is_empty() {
22823                return Ok(CompletionResponse {
22824                    completions: vec![],
22825                    display_options: CompletionDisplayOptions::default(),
22826                    is_incomplete: true,
22827                });
22828            }
22829
22830            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22831            let to_lsp = |point: &text::Anchor| {
22832                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22833                point_to_lsp(end)
22834            };
22835            let lsp_end = to_lsp(&buffer_position);
22836
22837            let candidates = snippets
22838                .iter()
22839                .enumerate()
22840                .flat_map(|(ix, snippet)| {
22841                    snippet
22842                        .prefix
22843                        .iter()
22844                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22845                })
22846                .collect::<Vec<StringMatchCandidate>>();
22847
22848            const MAX_RESULTS: usize = 100;
22849            let mut matches = fuzzy::match_strings(
22850                &candidates,
22851                &last_word,
22852                last_word.chars().any(|c| c.is_uppercase()),
22853                true,
22854                MAX_RESULTS,
22855                &Default::default(),
22856                executor.clone(),
22857            )
22858            .await;
22859
22860            if matches.len() >= MAX_RESULTS {
22861                is_incomplete = true;
22862            }
22863
22864            // Remove all candidates where the query's start does not match the start of any word in the candidate
22865            if let Some(query_start) = last_word.chars().next() {
22866                matches.retain(|string_match| {
22867                    split_words(&string_match.string).any(|word| {
22868                        // Check that the first codepoint of the word as lowercase matches the first
22869                        // codepoint of the query as lowercase
22870                        word.chars()
22871                            .flat_map(|codepoint| codepoint.to_lowercase())
22872                            .zip(query_start.to_lowercase())
22873                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22874                    })
22875                });
22876            }
22877
22878            let matched_strings = matches
22879                .into_iter()
22880                .map(|m| m.string)
22881                .collect::<HashSet<_>>();
22882
22883            completions.extend(snippets.iter().filter_map(|snippet| {
22884                let matching_prefix = snippet
22885                    .prefix
22886                    .iter()
22887                    .find(|prefix| matched_strings.contains(*prefix))?;
22888                let start = as_offset - last_word.len();
22889                let start = snapshot.anchor_before(start);
22890                let range = start..buffer_position;
22891                let lsp_start = to_lsp(&start);
22892                let lsp_range = lsp::Range {
22893                    start: lsp_start,
22894                    end: lsp_end,
22895                };
22896                Some(Completion {
22897                    replace_range: range,
22898                    new_text: snippet.body.clone(),
22899                    source: CompletionSource::Lsp {
22900                        insert_range: None,
22901                        server_id: LanguageServerId(usize::MAX),
22902                        resolved: true,
22903                        lsp_completion: Box::new(lsp::CompletionItem {
22904                            label: snippet.prefix.first().unwrap().clone(),
22905                            kind: Some(CompletionItemKind::SNIPPET),
22906                            label_details: snippet.description.as_ref().map(|description| {
22907                                lsp::CompletionItemLabelDetails {
22908                                    detail: Some(description.clone()),
22909                                    description: None,
22910                                }
22911                            }),
22912                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22913                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22914                                lsp::InsertReplaceEdit {
22915                                    new_text: snippet.body.clone(),
22916                                    insert: lsp_range,
22917                                    replace: lsp_range,
22918                                },
22919                            )),
22920                            filter_text: Some(snippet.body.clone()),
22921                            sort_text: Some(char::MAX.to_string()),
22922                            ..lsp::CompletionItem::default()
22923                        }),
22924                        lsp_defaults: None,
22925                    },
22926                    label: CodeLabel::plain(matching_prefix.clone(), None),
22927                    icon_path: None,
22928                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22929                        single_line: snippet.name.clone().into(),
22930                        plain_text: snippet
22931                            .description
22932                            .clone()
22933                            .map(|description| description.into()),
22934                    }),
22935                    insert_text_mode: None,
22936                    confirm: None,
22937                })
22938            }))
22939        }
22940
22941        Ok(CompletionResponse {
22942            completions,
22943            display_options: CompletionDisplayOptions::default(),
22944            is_incomplete,
22945        })
22946    })
22947}
22948
22949impl CompletionProvider for Entity<Project> {
22950    fn completions(
22951        &self,
22952        _excerpt_id: ExcerptId,
22953        buffer: &Entity<Buffer>,
22954        buffer_position: text::Anchor,
22955        options: CompletionContext,
22956        _window: &mut Window,
22957        cx: &mut Context<Editor>,
22958    ) -> Task<Result<Vec<CompletionResponse>>> {
22959        self.update(cx, |project, cx| {
22960            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22961            let project_completions = project.completions(buffer, buffer_position, options, cx);
22962            cx.background_spawn(async move {
22963                let mut responses = project_completions.await?;
22964                let snippets = snippets.await?;
22965                if !snippets.completions.is_empty() {
22966                    responses.push(snippets);
22967                }
22968                Ok(responses)
22969            })
22970        })
22971    }
22972
22973    fn resolve_completions(
22974        &self,
22975        buffer: Entity<Buffer>,
22976        completion_indices: Vec<usize>,
22977        completions: Rc<RefCell<Box<[Completion]>>>,
22978        cx: &mut Context<Editor>,
22979    ) -> Task<Result<bool>> {
22980        self.update(cx, |project, cx| {
22981            project.lsp_store().update(cx, |lsp_store, cx| {
22982                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22983            })
22984        })
22985    }
22986
22987    fn apply_additional_edits_for_completion(
22988        &self,
22989        buffer: Entity<Buffer>,
22990        completions: Rc<RefCell<Box<[Completion]>>>,
22991        completion_index: usize,
22992        push_to_history: bool,
22993        cx: &mut Context<Editor>,
22994    ) -> Task<Result<Option<language::Transaction>>> {
22995        self.update(cx, |project, cx| {
22996            project.lsp_store().update(cx, |lsp_store, cx| {
22997                lsp_store.apply_additional_edits_for_completion(
22998                    buffer,
22999                    completions,
23000                    completion_index,
23001                    push_to_history,
23002                    cx,
23003                )
23004            })
23005        })
23006    }
23007
23008    fn is_completion_trigger(
23009        &self,
23010        buffer: &Entity<Buffer>,
23011        position: language::Anchor,
23012        text: &str,
23013        trigger_in_words: bool,
23014        menu_is_open: bool,
23015        cx: &mut Context<Editor>,
23016    ) -> bool {
23017        let mut chars = text.chars();
23018        let char = if let Some(char) = chars.next() {
23019            char
23020        } else {
23021            return false;
23022        };
23023        if chars.next().is_some() {
23024            return false;
23025        }
23026
23027        let buffer = buffer.read(cx);
23028        let snapshot = buffer.snapshot();
23029        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23030            return false;
23031        }
23032        let classifier = snapshot
23033            .char_classifier_at(position)
23034            .scope_context(Some(CharScopeContext::Completion));
23035        if trigger_in_words && classifier.is_word(char) {
23036            return true;
23037        }
23038
23039        buffer.completion_triggers().contains(text)
23040    }
23041}
23042
23043impl SemanticsProvider for Entity<Project> {
23044    fn hover(
23045        &self,
23046        buffer: &Entity<Buffer>,
23047        position: text::Anchor,
23048        cx: &mut App,
23049    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23050        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23051    }
23052
23053    fn document_highlights(
23054        &self,
23055        buffer: &Entity<Buffer>,
23056        position: text::Anchor,
23057        cx: &mut App,
23058    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23059        Some(self.update(cx, |project, cx| {
23060            project.document_highlights(buffer, position, cx)
23061        }))
23062    }
23063
23064    fn definitions(
23065        &self,
23066        buffer: &Entity<Buffer>,
23067        position: text::Anchor,
23068        kind: GotoDefinitionKind,
23069        cx: &mut App,
23070    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23071        Some(self.update(cx, |project, cx| match kind {
23072            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23073            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23074            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23075            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23076        }))
23077    }
23078
23079    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23080        self.update(cx, |project, cx| {
23081            if project
23082                .active_debug_session(cx)
23083                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23084            {
23085                return true;
23086            }
23087
23088            buffer.update(cx, |buffer, cx| {
23089                project.any_language_server_supports_inlay_hints(buffer, cx)
23090            })
23091        })
23092    }
23093
23094    fn inline_values(
23095        &self,
23096        buffer_handle: Entity<Buffer>,
23097        range: Range<text::Anchor>,
23098        cx: &mut App,
23099    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23100        self.update(cx, |project, cx| {
23101            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23102
23103            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23104        })
23105    }
23106
23107    fn applicable_inlay_chunks(
23108        &self,
23109        buffer: &Entity<Buffer>,
23110        ranges: &[Range<text::Anchor>],
23111        cx: &mut App,
23112    ) -> Vec<Range<BufferRow>> {
23113        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23114            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23115        })
23116    }
23117
23118    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23119        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23120            lsp_store.invalidate_inlay_hints(for_buffers)
23121        });
23122    }
23123
23124    fn inlay_hints(
23125        &self,
23126        invalidate: InvalidationStrategy,
23127        buffer: Entity<Buffer>,
23128        ranges: Vec<Range<text::Anchor>>,
23129        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23130        cx: &mut App,
23131    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23132        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23133            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23134        }))
23135    }
23136
23137    fn range_for_rename(
23138        &self,
23139        buffer: &Entity<Buffer>,
23140        position: text::Anchor,
23141        cx: &mut App,
23142    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23143        Some(self.update(cx, |project, cx| {
23144            let buffer = buffer.clone();
23145            let task = project.prepare_rename(buffer.clone(), position, cx);
23146            cx.spawn(async move |_, cx| {
23147                Ok(match task.await? {
23148                    PrepareRenameResponse::Success(range) => Some(range),
23149                    PrepareRenameResponse::InvalidPosition => None,
23150                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23151                        // Fallback on using TreeSitter info to determine identifier range
23152                        buffer.read_with(cx, |buffer, _| {
23153                            let snapshot = buffer.snapshot();
23154                            let (range, kind) = snapshot.surrounding_word(position, None);
23155                            if kind != Some(CharKind::Word) {
23156                                return None;
23157                            }
23158                            Some(
23159                                snapshot.anchor_before(range.start)
23160                                    ..snapshot.anchor_after(range.end),
23161                            )
23162                        })?
23163                    }
23164                })
23165            })
23166        }))
23167    }
23168
23169    fn perform_rename(
23170        &self,
23171        buffer: &Entity<Buffer>,
23172        position: text::Anchor,
23173        new_name: String,
23174        cx: &mut App,
23175    ) -> Option<Task<Result<ProjectTransaction>>> {
23176        Some(self.update(cx, |project, cx| {
23177            project.perform_rename(buffer.clone(), position, new_name, cx)
23178        }))
23179    }
23180}
23181
23182fn consume_contiguous_rows(
23183    contiguous_row_selections: &mut Vec<Selection<Point>>,
23184    selection: &Selection<Point>,
23185    display_map: &DisplaySnapshot,
23186    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23187) -> (MultiBufferRow, MultiBufferRow) {
23188    contiguous_row_selections.push(selection.clone());
23189    let start_row = starting_row(selection, display_map);
23190    let mut end_row = ending_row(selection, display_map);
23191
23192    while let Some(next_selection) = selections.peek() {
23193        if next_selection.start.row <= end_row.0 {
23194            end_row = ending_row(next_selection, display_map);
23195            contiguous_row_selections.push(selections.next().unwrap().clone());
23196        } else {
23197            break;
23198        }
23199    }
23200    (start_row, end_row)
23201}
23202
23203fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23204    if selection.start.column > 0 {
23205        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23206    } else {
23207        MultiBufferRow(selection.start.row)
23208    }
23209}
23210
23211fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23212    if next_selection.end.column > 0 || next_selection.is_empty() {
23213        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23214    } else {
23215        MultiBufferRow(next_selection.end.row)
23216    }
23217}
23218
23219impl EditorSnapshot {
23220    pub fn remote_selections_in_range<'a>(
23221        &'a self,
23222        range: &'a Range<Anchor>,
23223        collaboration_hub: &dyn CollaborationHub,
23224        cx: &'a App,
23225    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23226        let participant_names = collaboration_hub.user_names(cx);
23227        let participant_indices = collaboration_hub.user_participant_indices(cx);
23228        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23229        let collaborators_by_replica_id = collaborators_by_peer_id
23230            .values()
23231            .map(|collaborator| (collaborator.replica_id, collaborator))
23232            .collect::<HashMap<_, _>>();
23233        self.buffer_snapshot()
23234            .selections_in_range(range, false)
23235            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23236                if replica_id == ReplicaId::AGENT {
23237                    Some(RemoteSelection {
23238                        replica_id,
23239                        selection,
23240                        cursor_shape,
23241                        line_mode,
23242                        collaborator_id: CollaboratorId::Agent,
23243                        user_name: Some("Agent".into()),
23244                        color: cx.theme().players().agent(),
23245                    })
23246                } else {
23247                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23248                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23249                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23250                    Some(RemoteSelection {
23251                        replica_id,
23252                        selection,
23253                        cursor_shape,
23254                        line_mode,
23255                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23256                        user_name,
23257                        color: if let Some(index) = participant_index {
23258                            cx.theme().players().color_for_participant(index.0)
23259                        } else {
23260                            cx.theme().players().absent()
23261                        },
23262                    })
23263                }
23264            })
23265    }
23266
23267    pub fn hunks_for_ranges(
23268        &self,
23269        ranges: impl IntoIterator<Item = Range<Point>>,
23270    ) -> Vec<MultiBufferDiffHunk> {
23271        let mut hunks = Vec::new();
23272        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23273            HashMap::default();
23274        for query_range in ranges {
23275            let query_rows =
23276                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23277            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23278                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23279            ) {
23280                // Include deleted hunks that are adjacent to the query range, because
23281                // otherwise they would be missed.
23282                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23283                if hunk.status().is_deleted() {
23284                    intersects_range |= hunk.row_range.start == query_rows.end;
23285                    intersects_range |= hunk.row_range.end == query_rows.start;
23286                }
23287                if intersects_range {
23288                    if !processed_buffer_rows
23289                        .entry(hunk.buffer_id)
23290                        .or_default()
23291                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23292                    {
23293                        continue;
23294                    }
23295                    hunks.push(hunk);
23296                }
23297            }
23298        }
23299
23300        hunks
23301    }
23302
23303    fn display_diff_hunks_for_rows<'a>(
23304        &'a self,
23305        display_rows: Range<DisplayRow>,
23306        folded_buffers: &'a HashSet<BufferId>,
23307    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23308        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23309        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23310
23311        self.buffer_snapshot()
23312            .diff_hunks_in_range(buffer_start..buffer_end)
23313            .filter_map(|hunk| {
23314                if folded_buffers.contains(&hunk.buffer_id) {
23315                    return None;
23316                }
23317
23318                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23319                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23320
23321                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23322                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23323
23324                let display_hunk = if hunk_display_start.column() != 0 {
23325                    DisplayDiffHunk::Folded {
23326                        display_row: hunk_display_start.row(),
23327                    }
23328                } else {
23329                    let mut end_row = hunk_display_end.row();
23330                    if hunk_display_end.column() > 0 {
23331                        end_row.0 += 1;
23332                    }
23333                    let is_created_file = hunk.is_created_file();
23334                    DisplayDiffHunk::Unfolded {
23335                        status: hunk.status(),
23336                        diff_base_byte_range: hunk.diff_base_byte_range,
23337                        display_row_range: hunk_display_start.row()..end_row,
23338                        multi_buffer_range: Anchor::range_in_buffer(
23339                            hunk.excerpt_id,
23340                            hunk.buffer_id,
23341                            hunk.buffer_range,
23342                        ),
23343                        is_created_file,
23344                    }
23345                };
23346
23347                Some(display_hunk)
23348            })
23349    }
23350
23351    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23352        self.display_snapshot
23353            .buffer_snapshot()
23354            .language_at(position)
23355    }
23356
23357    pub fn is_focused(&self) -> bool {
23358        self.is_focused
23359    }
23360
23361    pub fn placeholder_text(&self) -> Option<String> {
23362        self.placeholder_display_snapshot
23363            .as_ref()
23364            .map(|display_map| display_map.text())
23365    }
23366
23367    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23368        self.scroll_anchor.scroll_position(&self.display_snapshot)
23369    }
23370
23371    fn gutter_dimensions(
23372        &self,
23373        font_id: FontId,
23374        font_size: Pixels,
23375        max_line_number_width: Pixels,
23376        cx: &App,
23377    ) -> Option<GutterDimensions> {
23378        if !self.show_gutter {
23379            return None;
23380        }
23381
23382        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23383        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23384
23385        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23386            matches!(
23387                ProjectSettings::get_global(cx).git.git_gutter,
23388                GitGutterSetting::TrackedFiles
23389            )
23390        });
23391        let gutter_settings = EditorSettings::get_global(cx).gutter;
23392        let show_line_numbers = self
23393            .show_line_numbers
23394            .unwrap_or(gutter_settings.line_numbers);
23395        let line_gutter_width = if show_line_numbers {
23396            // Avoid flicker-like gutter resizes when the line number gains another digit by
23397            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23398            let min_width_for_number_on_gutter =
23399                ch_advance * gutter_settings.min_line_number_digits as f32;
23400            max_line_number_width.max(min_width_for_number_on_gutter)
23401        } else {
23402            0.0.into()
23403        };
23404
23405        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23406        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23407
23408        let git_blame_entries_width =
23409            self.git_blame_gutter_max_author_length
23410                .map(|max_author_length| {
23411                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23412                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23413
23414                    /// The number of characters to dedicate to gaps and margins.
23415                    const SPACING_WIDTH: usize = 4;
23416
23417                    let max_char_count = max_author_length.min(renderer.max_author_length())
23418                        + ::git::SHORT_SHA_LENGTH
23419                        + MAX_RELATIVE_TIMESTAMP.len()
23420                        + SPACING_WIDTH;
23421
23422                    ch_advance * max_char_count
23423                });
23424
23425        let is_singleton = self.buffer_snapshot().is_singleton();
23426
23427        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23428        left_padding += if !is_singleton {
23429            ch_width * 4.0
23430        } else if show_runnables || show_breakpoints {
23431            ch_width * 3.0
23432        } else if show_git_gutter && show_line_numbers {
23433            ch_width * 2.0
23434        } else if show_git_gutter || show_line_numbers {
23435            ch_width
23436        } else {
23437            px(0.)
23438        };
23439
23440        let shows_folds = is_singleton && gutter_settings.folds;
23441
23442        let right_padding = if shows_folds && show_line_numbers {
23443            ch_width * 4.0
23444        } else if shows_folds || (!is_singleton && show_line_numbers) {
23445            ch_width * 3.0
23446        } else if show_line_numbers {
23447            ch_width
23448        } else {
23449            px(0.)
23450        };
23451
23452        Some(GutterDimensions {
23453            left_padding,
23454            right_padding,
23455            width: line_gutter_width + left_padding + right_padding,
23456            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23457            git_blame_entries_width,
23458        })
23459    }
23460
23461    pub fn render_crease_toggle(
23462        &self,
23463        buffer_row: MultiBufferRow,
23464        row_contains_cursor: bool,
23465        editor: Entity<Editor>,
23466        window: &mut Window,
23467        cx: &mut App,
23468    ) -> Option<AnyElement> {
23469        let folded = self.is_line_folded(buffer_row);
23470        let mut is_foldable = false;
23471
23472        if let Some(crease) = self
23473            .crease_snapshot
23474            .query_row(buffer_row, self.buffer_snapshot())
23475        {
23476            is_foldable = true;
23477            match crease {
23478                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23479                    if let Some(render_toggle) = render_toggle {
23480                        let toggle_callback =
23481                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23482                                if folded {
23483                                    editor.update(cx, |editor, cx| {
23484                                        editor.fold_at(buffer_row, window, cx)
23485                                    });
23486                                } else {
23487                                    editor.update(cx, |editor, cx| {
23488                                        editor.unfold_at(buffer_row, window, cx)
23489                                    });
23490                                }
23491                            });
23492                        return Some((render_toggle)(
23493                            buffer_row,
23494                            folded,
23495                            toggle_callback,
23496                            window,
23497                            cx,
23498                        ));
23499                    }
23500                }
23501            }
23502        }
23503
23504        is_foldable |= self.starts_indent(buffer_row);
23505
23506        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23507            Some(
23508                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23509                    .toggle_state(folded)
23510                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23511                        if folded {
23512                            this.unfold_at(buffer_row, window, cx);
23513                        } else {
23514                            this.fold_at(buffer_row, window, cx);
23515                        }
23516                    }))
23517                    .into_any_element(),
23518            )
23519        } else {
23520            None
23521        }
23522    }
23523
23524    pub fn render_crease_trailer(
23525        &self,
23526        buffer_row: MultiBufferRow,
23527        window: &mut Window,
23528        cx: &mut App,
23529    ) -> Option<AnyElement> {
23530        let folded = self.is_line_folded(buffer_row);
23531        if let Crease::Inline { render_trailer, .. } = self
23532            .crease_snapshot
23533            .query_row(buffer_row, self.buffer_snapshot())?
23534        {
23535            let render_trailer = render_trailer.as_ref()?;
23536            Some(render_trailer(buffer_row, folded, window, cx))
23537        } else {
23538            None
23539        }
23540    }
23541}
23542
23543impl Deref for EditorSnapshot {
23544    type Target = DisplaySnapshot;
23545
23546    fn deref(&self) -> &Self::Target {
23547        &self.display_snapshot
23548    }
23549}
23550
23551#[derive(Clone, Debug, PartialEq, Eq)]
23552pub enum EditorEvent {
23553    InputIgnored {
23554        text: Arc<str>,
23555    },
23556    InputHandled {
23557        utf16_range_to_replace: Option<Range<isize>>,
23558        text: Arc<str>,
23559    },
23560    ExcerptsAdded {
23561        buffer: Entity<Buffer>,
23562        predecessor: ExcerptId,
23563        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23564    },
23565    ExcerptsRemoved {
23566        ids: Vec<ExcerptId>,
23567        removed_buffer_ids: Vec<BufferId>,
23568    },
23569    BufferFoldToggled {
23570        ids: Vec<ExcerptId>,
23571        folded: bool,
23572    },
23573    ExcerptsEdited {
23574        ids: Vec<ExcerptId>,
23575    },
23576    ExcerptsExpanded {
23577        ids: Vec<ExcerptId>,
23578    },
23579    BufferEdited,
23580    Edited {
23581        transaction_id: clock::Lamport,
23582    },
23583    Reparsed(BufferId),
23584    Focused,
23585    FocusedIn,
23586    Blurred,
23587    DirtyChanged,
23588    Saved,
23589    TitleChanged,
23590    SelectionsChanged {
23591        local: bool,
23592    },
23593    ScrollPositionChanged {
23594        local: bool,
23595        autoscroll: bool,
23596    },
23597    TransactionUndone {
23598        transaction_id: clock::Lamport,
23599    },
23600    TransactionBegun {
23601        transaction_id: clock::Lamport,
23602    },
23603    CursorShapeChanged,
23604    BreadcrumbsChanged,
23605    PushedToNavHistory {
23606        anchor: Anchor,
23607        is_deactivate: bool,
23608    },
23609}
23610
23611impl EventEmitter<EditorEvent> for Editor {}
23612
23613impl Focusable for Editor {
23614    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23615        self.focus_handle.clone()
23616    }
23617}
23618
23619impl Render for Editor {
23620    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23621        let settings = ThemeSettings::get_global(cx);
23622
23623        let mut text_style = match self.mode {
23624            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23625                color: cx.theme().colors().editor_foreground,
23626                font_family: settings.ui_font.family.clone(),
23627                font_features: settings.ui_font.features.clone(),
23628                font_fallbacks: settings.ui_font.fallbacks.clone(),
23629                font_size: rems(0.875).into(),
23630                font_weight: settings.ui_font.weight,
23631                line_height: relative(settings.buffer_line_height.value()),
23632                ..Default::default()
23633            },
23634            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23635                color: cx.theme().colors().editor_foreground,
23636                font_family: settings.buffer_font.family.clone(),
23637                font_features: settings.buffer_font.features.clone(),
23638                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23639                font_size: settings.buffer_font_size(cx).into(),
23640                font_weight: settings.buffer_font.weight,
23641                line_height: relative(settings.buffer_line_height.value()),
23642                ..Default::default()
23643            },
23644        };
23645        if let Some(text_style_refinement) = &self.text_style_refinement {
23646            text_style.refine(text_style_refinement)
23647        }
23648
23649        let background = match self.mode {
23650            EditorMode::SingleLine => cx.theme().system().transparent,
23651            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23652            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23653            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23654        };
23655
23656        EditorElement::new(
23657            &cx.entity(),
23658            EditorStyle {
23659                background,
23660                border: cx.theme().colors().border,
23661                local_player: cx.theme().players().local(),
23662                text: text_style,
23663                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23664                syntax: cx.theme().syntax().clone(),
23665                status: cx.theme().status().clone(),
23666                inlay_hints_style: make_inlay_hints_style(cx),
23667                edit_prediction_styles: make_suggestion_styles(cx),
23668                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23669                show_underlines: self.diagnostics_enabled(),
23670            },
23671        )
23672    }
23673}
23674
23675impl EntityInputHandler for Editor {
23676    fn text_for_range(
23677        &mut self,
23678        range_utf16: Range<usize>,
23679        adjusted_range: &mut Option<Range<usize>>,
23680        _: &mut Window,
23681        cx: &mut Context<Self>,
23682    ) -> Option<String> {
23683        let snapshot = self.buffer.read(cx).read(cx);
23684        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23685        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23686        if (start.0..end.0) != range_utf16 {
23687            adjusted_range.replace(start.0..end.0);
23688        }
23689        Some(snapshot.text_for_range(start..end).collect())
23690    }
23691
23692    fn selected_text_range(
23693        &mut self,
23694        ignore_disabled_input: bool,
23695        _: &mut Window,
23696        cx: &mut Context<Self>,
23697    ) -> Option<UTF16Selection> {
23698        // Prevent the IME menu from appearing when holding down an alphabetic key
23699        // while input is disabled.
23700        if !ignore_disabled_input && !self.input_enabled {
23701            return None;
23702        }
23703
23704        let selection = self
23705            .selections
23706            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23707        let range = selection.range();
23708
23709        Some(UTF16Selection {
23710            range: range.start.0..range.end.0,
23711            reversed: selection.reversed,
23712        })
23713    }
23714
23715    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23716        let snapshot = self.buffer.read(cx).read(cx);
23717        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23718        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23719    }
23720
23721    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23722        self.clear_highlights::<InputComposition>(cx);
23723        self.ime_transaction.take();
23724    }
23725
23726    fn replace_text_in_range(
23727        &mut self,
23728        range_utf16: Option<Range<usize>>,
23729        text: &str,
23730        window: &mut Window,
23731        cx: &mut Context<Self>,
23732    ) {
23733        if !self.input_enabled {
23734            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23735            return;
23736        }
23737
23738        self.transact(window, cx, |this, window, cx| {
23739            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23740                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23741                Some(this.selection_replacement_ranges(range_utf16, cx))
23742            } else {
23743                this.marked_text_ranges(cx)
23744            };
23745
23746            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23747                let newest_selection_id = this.selections.newest_anchor().id;
23748                this.selections
23749                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23750                    .iter()
23751                    .zip(ranges_to_replace.iter())
23752                    .find_map(|(selection, range)| {
23753                        if selection.id == newest_selection_id {
23754                            Some(
23755                                (range.start.0 as isize - selection.head().0 as isize)
23756                                    ..(range.end.0 as isize - selection.head().0 as isize),
23757                            )
23758                        } else {
23759                            None
23760                        }
23761                    })
23762            });
23763
23764            cx.emit(EditorEvent::InputHandled {
23765                utf16_range_to_replace: range_to_replace,
23766                text: text.into(),
23767            });
23768
23769            if let Some(new_selected_ranges) = new_selected_ranges {
23770                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23771                    selections.select_ranges(new_selected_ranges)
23772                });
23773                this.backspace(&Default::default(), window, cx);
23774            }
23775
23776            this.handle_input(text, window, cx);
23777        });
23778
23779        if let Some(transaction) = self.ime_transaction {
23780            self.buffer.update(cx, |buffer, cx| {
23781                buffer.group_until_transaction(transaction, cx);
23782            });
23783        }
23784
23785        self.unmark_text(window, cx);
23786    }
23787
23788    fn replace_and_mark_text_in_range(
23789        &mut self,
23790        range_utf16: Option<Range<usize>>,
23791        text: &str,
23792        new_selected_range_utf16: Option<Range<usize>>,
23793        window: &mut Window,
23794        cx: &mut Context<Self>,
23795    ) {
23796        if !self.input_enabled {
23797            return;
23798        }
23799
23800        let transaction = self.transact(window, cx, |this, window, cx| {
23801            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23802                let snapshot = this.buffer.read(cx).read(cx);
23803                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23804                    for marked_range in &mut marked_ranges {
23805                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23806                        marked_range.start.0 += relative_range_utf16.start;
23807                        marked_range.start =
23808                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23809                        marked_range.end =
23810                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23811                    }
23812                }
23813                Some(marked_ranges)
23814            } else if let Some(range_utf16) = range_utf16 {
23815                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23816                Some(this.selection_replacement_ranges(range_utf16, cx))
23817            } else {
23818                None
23819            };
23820
23821            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23822                let newest_selection_id = this.selections.newest_anchor().id;
23823                this.selections
23824                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23825                    .iter()
23826                    .zip(ranges_to_replace.iter())
23827                    .find_map(|(selection, range)| {
23828                        if selection.id == newest_selection_id {
23829                            Some(
23830                                (range.start.0 as isize - selection.head().0 as isize)
23831                                    ..(range.end.0 as isize - selection.head().0 as isize),
23832                            )
23833                        } else {
23834                            None
23835                        }
23836                    })
23837            });
23838
23839            cx.emit(EditorEvent::InputHandled {
23840                utf16_range_to_replace: range_to_replace,
23841                text: text.into(),
23842            });
23843
23844            if let Some(ranges) = ranges_to_replace {
23845                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23846                    s.select_ranges(ranges)
23847                });
23848            }
23849
23850            let marked_ranges = {
23851                let snapshot = this.buffer.read(cx).read(cx);
23852                this.selections
23853                    .disjoint_anchors_arc()
23854                    .iter()
23855                    .map(|selection| {
23856                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23857                    })
23858                    .collect::<Vec<_>>()
23859            };
23860
23861            if text.is_empty() {
23862                this.unmark_text(window, cx);
23863            } else {
23864                this.highlight_text::<InputComposition>(
23865                    marked_ranges.clone(),
23866                    HighlightStyle {
23867                        underline: Some(UnderlineStyle {
23868                            thickness: px(1.),
23869                            color: None,
23870                            wavy: false,
23871                        }),
23872                        ..Default::default()
23873                    },
23874                    cx,
23875                );
23876            }
23877
23878            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23879            let use_autoclose = this.use_autoclose;
23880            let use_auto_surround = this.use_auto_surround;
23881            this.set_use_autoclose(false);
23882            this.set_use_auto_surround(false);
23883            this.handle_input(text, window, cx);
23884            this.set_use_autoclose(use_autoclose);
23885            this.set_use_auto_surround(use_auto_surround);
23886
23887            if let Some(new_selected_range) = new_selected_range_utf16 {
23888                let snapshot = this.buffer.read(cx).read(cx);
23889                let new_selected_ranges = marked_ranges
23890                    .into_iter()
23891                    .map(|marked_range| {
23892                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23893                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23894                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23895                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23896                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23897                    })
23898                    .collect::<Vec<_>>();
23899
23900                drop(snapshot);
23901                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23902                    selections.select_ranges(new_selected_ranges)
23903                });
23904            }
23905        });
23906
23907        self.ime_transaction = self.ime_transaction.or(transaction);
23908        if let Some(transaction) = self.ime_transaction {
23909            self.buffer.update(cx, |buffer, cx| {
23910                buffer.group_until_transaction(transaction, cx);
23911            });
23912        }
23913
23914        if self.text_highlights::<InputComposition>(cx).is_none() {
23915            self.ime_transaction.take();
23916        }
23917    }
23918
23919    fn bounds_for_range(
23920        &mut self,
23921        range_utf16: Range<usize>,
23922        element_bounds: gpui::Bounds<Pixels>,
23923        window: &mut Window,
23924        cx: &mut Context<Self>,
23925    ) -> Option<gpui::Bounds<Pixels>> {
23926        let text_layout_details = self.text_layout_details(window);
23927        let CharacterDimensions {
23928            em_width,
23929            em_advance,
23930            line_height,
23931        } = self.character_dimensions(window);
23932
23933        let snapshot = self.snapshot(window, cx);
23934        let scroll_position = snapshot.scroll_position();
23935        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
23936
23937        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23938        let x = Pixels::from(
23939            ScrollOffset::from(
23940                snapshot.x_for_display_point(start, &text_layout_details)
23941                    + self.gutter_dimensions.full_width(),
23942            ) - scroll_left,
23943        );
23944        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
23945
23946        Some(Bounds {
23947            origin: element_bounds.origin + point(x, y),
23948            size: size(em_width, line_height),
23949        })
23950    }
23951
23952    fn character_index_for_point(
23953        &mut self,
23954        point: gpui::Point<Pixels>,
23955        _window: &mut Window,
23956        _cx: &mut Context<Self>,
23957    ) -> Option<usize> {
23958        let position_map = self.last_position_map.as_ref()?;
23959        if !position_map.text_hitbox.contains(&point) {
23960            return None;
23961        }
23962        let display_point = position_map.point_for_position(point).previous_valid;
23963        let anchor = position_map
23964            .snapshot
23965            .display_point_to_anchor(display_point, Bias::Left);
23966        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
23967        Some(utf16_offset.0)
23968    }
23969}
23970
23971trait SelectionExt {
23972    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23973    fn spanned_rows(
23974        &self,
23975        include_end_if_at_line_start: bool,
23976        map: &DisplaySnapshot,
23977    ) -> Range<MultiBufferRow>;
23978}
23979
23980impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23981    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23982        let start = self
23983            .start
23984            .to_point(map.buffer_snapshot())
23985            .to_display_point(map);
23986        let end = self
23987            .end
23988            .to_point(map.buffer_snapshot())
23989            .to_display_point(map);
23990        if self.reversed {
23991            end..start
23992        } else {
23993            start..end
23994        }
23995    }
23996
23997    fn spanned_rows(
23998        &self,
23999        include_end_if_at_line_start: bool,
24000        map: &DisplaySnapshot,
24001    ) -> Range<MultiBufferRow> {
24002        let start = self.start.to_point(map.buffer_snapshot());
24003        let mut end = self.end.to_point(map.buffer_snapshot());
24004        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24005            end.row -= 1;
24006        }
24007
24008        let buffer_start = map.prev_line_boundary(start).0;
24009        let buffer_end = map.next_line_boundary(end).0;
24010        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24011    }
24012}
24013
24014impl<T: InvalidationRegion> InvalidationStack<T> {
24015    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24016    where
24017        S: Clone + ToOffset,
24018    {
24019        while let Some(region) = self.last() {
24020            let all_selections_inside_invalidation_ranges =
24021                if selections.len() == region.ranges().len() {
24022                    selections
24023                        .iter()
24024                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24025                        .all(|(selection, invalidation_range)| {
24026                            let head = selection.head().to_offset(buffer);
24027                            invalidation_range.start <= head && invalidation_range.end >= head
24028                        })
24029                } else {
24030                    false
24031                };
24032
24033            if all_selections_inside_invalidation_ranges {
24034                break;
24035            } else {
24036                self.pop();
24037            }
24038        }
24039    }
24040}
24041
24042impl<T> Default for InvalidationStack<T> {
24043    fn default() -> Self {
24044        Self(Default::default())
24045    }
24046}
24047
24048impl<T> Deref for InvalidationStack<T> {
24049    type Target = Vec<T>;
24050
24051    fn deref(&self) -> &Self::Target {
24052        &self.0
24053    }
24054}
24055
24056impl<T> DerefMut for InvalidationStack<T> {
24057    fn deref_mut(&mut self) -> &mut Self::Target {
24058        &mut self.0
24059    }
24060}
24061
24062impl InvalidationRegion for SnippetState {
24063    fn ranges(&self) -> &[Range<Anchor>] {
24064        &self.ranges[self.active_index]
24065    }
24066}
24067
24068fn edit_prediction_edit_text(
24069    current_snapshot: &BufferSnapshot,
24070    edits: &[(Range<Anchor>, String)],
24071    edit_preview: &EditPreview,
24072    include_deletions: bool,
24073    cx: &App,
24074) -> HighlightedText {
24075    let edits = edits
24076        .iter()
24077        .map(|(anchor, text)| {
24078            (
24079                anchor.start.text_anchor..anchor.end.text_anchor,
24080                text.clone(),
24081            )
24082        })
24083        .collect::<Vec<_>>();
24084
24085    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24086}
24087
24088fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24089    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24090    // Just show the raw edit text with basic styling
24091    let mut text = String::new();
24092    let mut highlights = Vec::new();
24093
24094    let insertion_highlight_style = HighlightStyle {
24095        color: Some(cx.theme().colors().text),
24096        ..Default::default()
24097    };
24098
24099    for (_, edit_text) in edits {
24100        let start_offset = text.len();
24101        text.push_str(edit_text);
24102        let end_offset = text.len();
24103
24104        if start_offset < end_offset {
24105            highlights.push((start_offset..end_offset, insertion_highlight_style));
24106        }
24107    }
24108
24109    HighlightedText {
24110        text: text.into(),
24111        highlights,
24112    }
24113}
24114
24115pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24116    match severity {
24117        lsp::DiagnosticSeverity::ERROR => colors.error,
24118        lsp::DiagnosticSeverity::WARNING => colors.warning,
24119        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24120        lsp::DiagnosticSeverity::HINT => colors.info,
24121        _ => colors.ignored,
24122    }
24123}
24124
24125pub fn styled_runs_for_code_label<'a>(
24126    label: &'a CodeLabel,
24127    syntax_theme: &'a theme::SyntaxTheme,
24128) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24129    let fade_out = HighlightStyle {
24130        fade_out: Some(0.35),
24131        ..Default::default()
24132    };
24133
24134    let mut prev_end = label.filter_range.end;
24135    label
24136        .runs
24137        .iter()
24138        .enumerate()
24139        .flat_map(move |(ix, (range, highlight_id))| {
24140            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24141                style
24142            } else {
24143                return Default::default();
24144            };
24145            let muted_style = style.highlight(fade_out);
24146
24147            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24148            if range.start >= label.filter_range.end {
24149                if range.start > prev_end {
24150                    runs.push((prev_end..range.start, fade_out));
24151                }
24152                runs.push((range.clone(), muted_style));
24153            } else if range.end <= label.filter_range.end {
24154                runs.push((range.clone(), style));
24155            } else {
24156                runs.push((range.start..label.filter_range.end, style));
24157                runs.push((label.filter_range.end..range.end, muted_style));
24158            }
24159            prev_end = cmp::max(prev_end, range.end);
24160
24161            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24162                runs.push((prev_end..label.text.len(), fade_out));
24163            }
24164
24165            runs
24166        })
24167}
24168
24169pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24170    let mut prev_index = 0;
24171    let mut prev_codepoint: Option<char> = None;
24172    text.char_indices()
24173        .chain([(text.len(), '\0')])
24174        .filter_map(move |(index, codepoint)| {
24175            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24176            let is_boundary = index == text.len()
24177                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24178                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24179            if is_boundary {
24180                let chunk = &text[prev_index..index];
24181                prev_index = index;
24182                Some(chunk)
24183            } else {
24184                None
24185            }
24186        })
24187}
24188
24189pub trait RangeToAnchorExt: Sized {
24190    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24191
24192    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24193        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24194        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24195    }
24196}
24197
24198impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24199    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24200        let start_offset = self.start.to_offset(snapshot);
24201        let end_offset = self.end.to_offset(snapshot);
24202        if start_offset == end_offset {
24203            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24204        } else {
24205            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24206        }
24207    }
24208}
24209
24210pub trait RowExt {
24211    fn as_f64(&self) -> f64;
24212
24213    fn next_row(&self) -> Self;
24214
24215    fn previous_row(&self) -> Self;
24216
24217    fn minus(&self, other: Self) -> u32;
24218}
24219
24220impl RowExt for DisplayRow {
24221    fn as_f64(&self) -> f64 {
24222        self.0 as _
24223    }
24224
24225    fn next_row(&self) -> Self {
24226        Self(self.0 + 1)
24227    }
24228
24229    fn previous_row(&self) -> Self {
24230        Self(self.0.saturating_sub(1))
24231    }
24232
24233    fn minus(&self, other: Self) -> u32 {
24234        self.0 - other.0
24235    }
24236}
24237
24238impl RowExt for MultiBufferRow {
24239    fn as_f64(&self) -> f64 {
24240        self.0 as _
24241    }
24242
24243    fn next_row(&self) -> Self {
24244        Self(self.0 + 1)
24245    }
24246
24247    fn previous_row(&self) -> Self {
24248        Self(self.0.saturating_sub(1))
24249    }
24250
24251    fn minus(&self, other: Self) -> u32 {
24252        self.0 - other.0
24253    }
24254}
24255
24256trait RowRangeExt {
24257    type Row;
24258
24259    fn len(&self) -> usize;
24260
24261    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24262}
24263
24264impl RowRangeExt for Range<MultiBufferRow> {
24265    type Row = MultiBufferRow;
24266
24267    fn len(&self) -> usize {
24268        (self.end.0 - self.start.0) as usize
24269    }
24270
24271    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24272        (self.start.0..self.end.0).map(MultiBufferRow)
24273    }
24274}
24275
24276impl RowRangeExt for Range<DisplayRow> {
24277    type Row = DisplayRow;
24278
24279    fn len(&self) -> usize {
24280        (self.end.0 - self.start.0) as usize
24281    }
24282
24283    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24284        (self.start.0..self.end.0).map(DisplayRow)
24285    }
24286}
24287
24288/// If select range has more than one line, we
24289/// just point the cursor to range.start.
24290fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24291    if range.start.row == range.end.row {
24292        range
24293    } else {
24294        range.start..range.start
24295    }
24296}
24297pub struct KillRing(ClipboardItem);
24298impl Global for KillRing {}
24299
24300const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24301
24302enum BreakpointPromptEditAction {
24303    Log,
24304    Condition,
24305    HitCondition,
24306}
24307
24308struct BreakpointPromptEditor {
24309    pub(crate) prompt: Entity<Editor>,
24310    editor: WeakEntity<Editor>,
24311    breakpoint_anchor: Anchor,
24312    breakpoint: Breakpoint,
24313    edit_action: BreakpointPromptEditAction,
24314    block_ids: HashSet<CustomBlockId>,
24315    editor_margins: Arc<Mutex<EditorMargins>>,
24316    _subscriptions: Vec<Subscription>,
24317}
24318
24319impl BreakpointPromptEditor {
24320    const MAX_LINES: u8 = 4;
24321
24322    fn new(
24323        editor: WeakEntity<Editor>,
24324        breakpoint_anchor: Anchor,
24325        breakpoint: Breakpoint,
24326        edit_action: BreakpointPromptEditAction,
24327        window: &mut Window,
24328        cx: &mut Context<Self>,
24329    ) -> Self {
24330        let base_text = match edit_action {
24331            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24332            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24333            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24334        }
24335        .map(|msg| msg.to_string())
24336        .unwrap_or_default();
24337
24338        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24339        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24340
24341        let prompt = cx.new(|cx| {
24342            let mut prompt = Editor::new(
24343                EditorMode::AutoHeight {
24344                    min_lines: 1,
24345                    max_lines: Some(Self::MAX_LINES as usize),
24346                },
24347                buffer,
24348                None,
24349                window,
24350                cx,
24351            );
24352            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24353            prompt.set_show_cursor_when_unfocused(false, cx);
24354            prompt.set_placeholder_text(
24355                match edit_action {
24356                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24357                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24358                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24359                },
24360                window,
24361                cx,
24362            );
24363
24364            prompt
24365        });
24366
24367        Self {
24368            prompt,
24369            editor,
24370            breakpoint_anchor,
24371            breakpoint,
24372            edit_action,
24373            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24374            block_ids: Default::default(),
24375            _subscriptions: vec![],
24376        }
24377    }
24378
24379    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24380        self.block_ids.extend(block_ids)
24381    }
24382
24383    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24384        if let Some(editor) = self.editor.upgrade() {
24385            let message = self
24386                .prompt
24387                .read(cx)
24388                .buffer
24389                .read(cx)
24390                .as_singleton()
24391                .expect("A multi buffer in breakpoint prompt isn't possible")
24392                .read(cx)
24393                .as_rope()
24394                .to_string();
24395
24396            editor.update(cx, |editor, cx| {
24397                editor.edit_breakpoint_at_anchor(
24398                    self.breakpoint_anchor,
24399                    self.breakpoint.clone(),
24400                    match self.edit_action {
24401                        BreakpointPromptEditAction::Log => {
24402                            BreakpointEditAction::EditLogMessage(message.into())
24403                        }
24404                        BreakpointPromptEditAction::Condition => {
24405                            BreakpointEditAction::EditCondition(message.into())
24406                        }
24407                        BreakpointPromptEditAction::HitCondition => {
24408                            BreakpointEditAction::EditHitCondition(message.into())
24409                        }
24410                    },
24411                    cx,
24412                );
24413
24414                editor.remove_blocks(self.block_ids.clone(), None, cx);
24415                cx.focus_self(window);
24416            });
24417        }
24418    }
24419
24420    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24421        self.editor
24422            .update(cx, |editor, cx| {
24423                editor.remove_blocks(self.block_ids.clone(), None, cx);
24424                window.focus(&editor.focus_handle);
24425            })
24426            .log_err();
24427    }
24428
24429    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24430        let settings = ThemeSettings::get_global(cx);
24431        let text_style = TextStyle {
24432            color: if self.prompt.read(cx).read_only(cx) {
24433                cx.theme().colors().text_disabled
24434            } else {
24435                cx.theme().colors().text
24436            },
24437            font_family: settings.buffer_font.family.clone(),
24438            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24439            font_size: settings.buffer_font_size(cx).into(),
24440            font_weight: settings.buffer_font.weight,
24441            line_height: relative(settings.buffer_line_height.value()),
24442            ..Default::default()
24443        };
24444        EditorElement::new(
24445            &self.prompt,
24446            EditorStyle {
24447                background: cx.theme().colors().editor_background,
24448                local_player: cx.theme().players().local(),
24449                text: text_style,
24450                ..Default::default()
24451            },
24452        )
24453    }
24454}
24455
24456impl Render for BreakpointPromptEditor {
24457    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24458        let editor_margins = *self.editor_margins.lock();
24459        let gutter_dimensions = editor_margins.gutter;
24460        h_flex()
24461            .key_context("Editor")
24462            .bg(cx.theme().colors().editor_background)
24463            .border_y_1()
24464            .border_color(cx.theme().status().info_border)
24465            .size_full()
24466            .py(window.line_height() / 2.5)
24467            .on_action(cx.listener(Self::confirm))
24468            .on_action(cx.listener(Self::cancel))
24469            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24470            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24471    }
24472}
24473
24474impl Focusable for BreakpointPromptEditor {
24475    fn focus_handle(&self, cx: &App) -> FocusHandle {
24476        self.prompt.focus_handle(cx)
24477    }
24478}
24479
24480fn all_edits_insertions_or_deletions(
24481    edits: &Vec<(Range<Anchor>, String)>,
24482    snapshot: &MultiBufferSnapshot,
24483) -> bool {
24484    let mut all_insertions = true;
24485    let mut all_deletions = true;
24486
24487    for (range, new_text) in edits.iter() {
24488        let range_is_empty = range.to_offset(snapshot).is_empty();
24489        let text_is_empty = new_text.is_empty();
24490
24491        if range_is_empty != text_is_empty {
24492            if range_is_empty {
24493                all_deletions = false;
24494            } else {
24495                all_insertions = false;
24496            }
24497        } else {
24498            return false;
24499        }
24500
24501        if !all_insertions && !all_deletions {
24502            return false;
24503        }
24504    }
24505    all_insertions || all_deletions
24506}
24507
24508struct MissingEditPredictionKeybindingTooltip;
24509
24510impl Render for MissingEditPredictionKeybindingTooltip {
24511    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24512        ui::tooltip_container(cx, |container, cx| {
24513            container
24514                .flex_shrink_0()
24515                .max_w_80()
24516                .min_h(rems_from_px(124.))
24517                .justify_between()
24518                .child(
24519                    v_flex()
24520                        .flex_1()
24521                        .text_ui_sm(cx)
24522                        .child(Label::new("Conflict with Accept Keybinding"))
24523                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24524                )
24525                .child(
24526                    h_flex()
24527                        .pb_1()
24528                        .gap_1()
24529                        .items_end()
24530                        .w_full()
24531                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24532                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24533                        }))
24534                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24535                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24536                        })),
24537                )
24538        })
24539    }
24540}
24541
24542#[derive(Debug, Clone, Copy, PartialEq)]
24543pub struct LineHighlight {
24544    pub background: Background,
24545    pub border: Option<gpui::Hsla>,
24546    pub include_gutter: bool,
24547    pub type_id: Option<TypeId>,
24548}
24549
24550struct LineManipulationResult {
24551    pub new_text: String,
24552    pub line_count_before: usize,
24553    pub line_count_after: usize,
24554}
24555
24556fn render_diff_hunk_controls(
24557    row: u32,
24558    status: &DiffHunkStatus,
24559    hunk_range: Range<Anchor>,
24560    is_created_file: bool,
24561    line_height: Pixels,
24562    editor: &Entity<Editor>,
24563    _window: &mut Window,
24564    cx: &mut App,
24565) -> AnyElement {
24566    h_flex()
24567        .h(line_height)
24568        .mr_1()
24569        .gap_1()
24570        .px_0p5()
24571        .pb_1()
24572        .border_x_1()
24573        .border_b_1()
24574        .border_color(cx.theme().colors().border_variant)
24575        .rounded_b_lg()
24576        .bg(cx.theme().colors().editor_background)
24577        .gap_1()
24578        .block_mouse_except_scroll()
24579        .shadow_md()
24580        .child(if status.has_secondary_hunk() {
24581            Button::new(("stage", row as u64), "Stage")
24582                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24583                .tooltip({
24584                    let focus_handle = editor.focus_handle(cx);
24585                    move |_window, cx| {
24586                        Tooltip::for_action_in(
24587                            "Stage Hunk",
24588                            &::git::ToggleStaged,
24589                            &focus_handle,
24590                            cx,
24591                        )
24592                    }
24593                })
24594                .on_click({
24595                    let editor = editor.clone();
24596                    move |_event, _window, cx| {
24597                        editor.update(cx, |editor, cx| {
24598                            editor.stage_or_unstage_diff_hunks(
24599                                true,
24600                                vec![hunk_range.start..hunk_range.start],
24601                                cx,
24602                            );
24603                        });
24604                    }
24605                })
24606        } else {
24607            Button::new(("unstage", row as u64), "Unstage")
24608                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24609                .tooltip({
24610                    let focus_handle = editor.focus_handle(cx);
24611                    move |_window, cx| {
24612                        Tooltip::for_action_in(
24613                            "Unstage Hunk",
24614                            &::git::ToggleStaged,
24615                            &focus_handle,
24616                            cx,
24617                        )
24618                    }
24619                })
24620                .on_click({
24621                    let editor = editor.clone();
24622                    move |_event, _window, cx| {
24623                        editor.update(cx, |editor, cx| {
24624                            editor.stage_or_unstage_diff_hunks(
24625                                false,
24626                                vec![hunk_range.start..hunk_range.start],
24627                                cx,
24628                            );
24629                        });
24630                    }
24631                })
24632        })
24633        .child(
24634            Button::new(("restore", row as u64), "Restore")
24635                .tooltip({
24636                    let focus_handle = editor.focus_handle(cx);
24637                    move |_window, cx| {
24638                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24639                    }
24640                })
24641                .on_click({
24642                    let editor = editor.clone();
24643                    move |_event, window, cx| {
24644                        editor.update(cx, |editor, cx| {
24645                            let snapshot = editor.snapshot(window, cx);
24646                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24647                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24648                        });
24649                    }
24650                })
24651                .disabled(is_created_file),
24652        )
24653        .when(
24654            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24655            |el| {
24656                el.child(
24657                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24658                        .shape(IconButtonShape::Square)
24659                        .icon_size(IconSize::Small)
24660                        // .disabled(!has_multiple_hunks)
24661                        .tooltip({
24662                            let focus_handle = editor.focus_handle(cx);
24663                            move |_window, cx| {
24664                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24665                            }
24666                        })
24667                        .on_click({
24668                            let editor = editor.clone();
24669                            move |_event, window, cx| {
24670                                editor.update(cx, |editor, cx| {
24671                                    let snapshot = editor.snapshot(window, cx);
24672                                    let position =
24673                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24674                                    editor.go_to_hunk_before_or_after_position(
24675                                        &snapshot,
24676                                        position,
24677                                        Direction::Next,
24678                                        window,
24679                                        cx,
24680                                    );
24681                                    editor.expand_selected_diff_hunks(cx);
24682                                });
24683                            }
24684                        }),
24685                )
24686                .child(
24687                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24688                        .shape(IconButtonShape::Square)
24689                        .icon_size(IconSize::Small)
24690                        // .disabled(!has_multiple_hunks)
24691                        .tooltip({
24692                            let focus_handle = editor.focus_handle(cx);
24693                            move |_window, cx| {
24694                                Tooltip::for_action_in(
24695                                    "Previous Hunk",
24696                                    &GoToPreviousHunk,
24697                                    &focus_handle,
24698                                    cx,
24699                                )
24700                            }
24701                        })
24702                        .on_click({
24703                            let editor = editor.clone();
24704                            move |_event, window, cx| {
24705                                editor.update(cx, |editor, cx| {
24706                                    let snapshot = editor.snapshot(window, cx);
24707                                    let point =
24708                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24709                                    editor.go_to_hunk_before_or_after_position(
24710                                        &snapshot,
24711                                        point,
24712                                        Direction::Prev,
24713                                        window,
24714                                        cx,
24715                                    );
24716                                    editor.expand_selected_diff_hunks(cx);
24717                                });
24718                            }
24719                        }),
24720                )
24721            },
24722        )
24723        .into_any_element()
24724}
24725
24726pub fn multibuffer_context_lines(cx: &App) -> u32 {
24727    EditorSettings::try_get(cx)
24728        .map(|settings| settings.excerpt_context_lines)
24729        .unwrap_or(2)
24730        .min(32)
24731}