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                            Rope::from_str_small(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_adjusted(&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                let bytes_after_last_selection =
14336                    buffer.bytes_in_range(last_selection.end..buffer.len());
14337                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14338                let query_matches = query
14339                    .stream_find_iter(bytes_after_last_selection)
14340                    .map(|result| (last_selection.end, result))
14341                    .chain(
14342                        query
14343                            .stream_find_iter(bytes_before_first_selection)
14344                            .map(|result| (0, result)),
14345                    );
14346
14347                for (start_offset, query_match) in query_matches {
14348                    let query_match = query_match.unwrap(); // can only fail due to I/O
14349                    let offset_range =
14350                        start_offset + query_match.start()..start_offset + query_match.end();
14351
14352                    if !select_next_state.wordwise
14353                        || (!buffer.is_inside_word(offset_range.start, None)
14354                            && !buffer.is_inside_word(offset_range.end, None))
14355                    {
14356                        let idx = selections
14357                            .partition_point(|selection| selection.end <= offset_range.start);
14358                        let overlaps = selections
14359                            .get(idx)
14360                            .map_or(false, |selection| selection.start < offset_range.end);
14361
14362                        if !overlaps {
14363                            next_selected_range = Some(offset_range);
14364                            break;
14365                        }
14366                    }
14367                }
14368
14369                if let Some(next_selected_range) = next_selected_range {
14370                    self.select_match_ranges(
14371                        next_selected_range,
14372                        last_selection.reversed,
14373                        replace_newest,
14374                        autoscroll,
14375                        window,
14376                        cx,
14377                    );
14378                } else {
14379                    select_next_state.done = true;
14380                }
14381            }
14382
14383            self.select_next_state = Some(select_next_state);
14384        } else {
14385            let mut only_carets = true;
14386            let mut same_text_selected = true;
14387            let mut selected_text = None;
14388
14389            let mut selections_iter = selections.iter().peekable();
14390            while let Some(selection) = selections_iter.next() {
14391                if selection.start != selection.end {
14392                    only_carets = false;
14393                }
14394
14395                if same_text_selected {
14396                    if selected_text.is_none() {
14397                        selected_text =
14398                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14399                    }
14400
14401                    if let Some(next_selection) = selections_iter.peek() {
14402                        if next_selection.range().len() == selection.range().len() {
14403                            let next_selected_text = buffer
14404                                .text_for_range(next_selection.range())
14405                                .collect::<String>();
14406                            if Some(next_selected_text) != selected_text {
14407                                same_text_selected = false;
14408                                selected_text = None;
14409                            }
14410                        } else {
14411                            same_text_selected = false;
14412                            selected_text = None;
14413                        }
14414                    }
14415                }
14416            }
14417
14418            if only_carets {
14419                for selection in &mut selections {
14420                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14421                    selection.start = word_range.start;
14422                    selection.end = word_range.end;
14423                    selection.goal = SelectionGoal::None;
14424                    selection.reversed = false;
14425                    self.select_match_ranges(
14426                        selection.start..selection.end,
14427                        selection.reversed,
14428                        replace_newest,
14429                        autoscroll,
14430                        window,
14431                        cx,
14432                    );
14433                }
14434
14435                if selections.len() == 1 {
14436                    let selection = selections
14437                        .last()
14438                        .expect("ensured that there's only one selection");
14439                    let query = buffer
14440                        .text_for_range(selection.start..selection.end)
14441                        .collect::<String>();
14442                    let is_empty = query.is_empty();
14443                    let select_state = SelectNextState {
14444                        query: AhoCorasick::new(&[query])?,
14445                        wordwise: true,
14446                        done: is_empty,
14447                    };
14448                    self.select_next_state = Some(select_state);
14449                } else {
14450                    self.select_next_state = None;
14451                }
14452            } else if let Some(selected_text) = selected_text {
14453                self.select_next_state = Some(SelectNextState {
14454                    query: AhoCorasick::new(&[selected_text])?,
14455                    wordwise: false,
14456                    done: false,
14457                });
14458                self.select_next_match_internal(
14459                    display_map,
14460                    replace_newest,
14461                    autoscroll,
14462                    window,
14463                    cx,
14464                )?;
14465            }
14466        }
14467        Ok(())
14468    }
14469
14470    pub fn select_all_matches(
14471        &mut self,
14472        _action: &SelectAllMatches,
14473        window: &mut Window,
14474        cx: &mut Context<Self>,
14475    ) -> Result<()> {
14476        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14477
14478        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14479
14480        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14481        let Some(select_next_state) = self.select_next_state.as_mut() else {
14482            return Ok(());
14483        };
14484        if select_next_state.done {
14485            return Ok(());
14486        }
14487
14488        let mut new_selections = Vec::new();
14489
14490        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14491        let buffer = display_map.buffer_snapshot();
14492        let query_matches = select_next_state
14493            .query
14494            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14495
14496        for query_match in query_matches.into_iter() {
14497            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14498            let offset_range = if reversed {
14499                query_match.end()..query_match.start()
14500            } else {
14501                query_match.start()..query_match.end()
14502            };
14503
14504            if !select_next_state.wordwise
14505                || (!buffer.is_inside_word(offset_range.start, None)
14506                    && !buffer.is_inside_word(offset_range.end, None))
14507            {
14508                new_selections.push(offset_range.start..offset_range.end);
14509            }
14510        }
14511
14512        select_next_state.done = true;
14513
14514        if new_selections.is_empty() {
14515            log::error!("bug: new_selections is empty in select_all_matches");
14516            return Ok(());
14517        }
14518
14519        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14520        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14521            selections.select_ranges(new_selections)
14522        });
14523
14524        Ok(())
14525    }
14526
14527    pub fn select_next(
14528        &mut self,
14529        action: &SelectNext,
14530        window: &mut Window,
14531        cx: &mut Context<Self>,
14532    ) -> Result<()> {
14533        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14534        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14535        self.select_next_match_internal(
14536            &display_map,
14537            action.replace_newest,
14538            Some(Autoscroll::newest()),
14539            window,
14540            cx,
14541        )?;
14542        Ok(())
14543    }
14544
14545    pub fn select_previous(
14546        &mut self,
14547        action: &SelectPrevious,
14548        window: &mut Window,
14549        cx: &mut Context<Self>,
14550    ) -> Result<()> {
14551        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14552        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14553        let buffer = display_map.buffer_snapshot();
14554        let mut selections = self.selections.all::<usize>(&display_map);
14555        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14556            let query = &select_prev_state.query;
14557            if !select_prev_state.done {
14558                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14559                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14560                let mut next_selected_range = None;
14561                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14562                let bytes_before_last_selection =
14563                    buffer.reversed_bytes_in_range(0..last_selection.start);
14564                let bytes_after_first_selection =
14565                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14566                let query_matches = query
14567                    .stream_find_iter(bytes_before_last_selection)
14568                    .map(|result| (last_selection.start, result))
14569                    .chain(
14570                        query
14571                            .stream_find_iter(bytes_after_first_selection)
14572                            .map(|result| (buffer.len(), result)),
14573                    );
14574                for (end_offset, query_match) in query_matches {
14575                    let query_match = query_match.unwrap(); // can only fail due to I/O
14576                    let offset_range =
14577                        end_offset - query_match.end()..end_offset - query_match.start();
14578
14579                    if !select_prev_state.wordwise
14580                        || (!buffer.is_inside_word(offset_range.start, None)
14581                            && !buffer.is_inside_word(offset_range.end, None))
14582                    {
14583                        next_selected_range = Some(offset_range);
14584                        break;
14585                    }
14586                }
14587
14588                if let Some(next_selected_range) = next_selected_range {
14589                    self.select_match_ranges(
14590                        next_selected_range,
14591                        last_selection.reversed,
14592                        action.replace_newest,
14593                        Some(Autoscroll::newest()),
14594                        window,
14595                        cx,
14596                    );
14597                } else {
14598                    select_prev_state.done = true;
14599                }
14600            }
14601
14602            self.select_prev_state = Some(select_prev_state);
14603        } else {
14604            let mut only_carets = true;
14605            let mut same_text_selected = true;
14606            let mut selected_text = None;
14607
14608            let mut selections_iter = selections.iter().peekable();
14609            while let Some(selection) = selections_iter.next() {
14610                if selection.start != selection.end {
14611                    only_carets = false;
14612                }
14613
14614                if same_text_selected {
14615                    if selected_text.is_none() {
14616                        selected_text =
14617                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14618                    }
14619
14620                    if let Some(next_selection) = selections_iter.peek() {
14621                        if next_selection.range().len() == selection.range().len() {
14622                            let next_selected_text = buffer
14623                                .text_for_range(next_selection.range())
14624                                .collect::<String>();
14625                            if Some(next_selected_text) != selected_text {
14626                                same_text_selected = false;
14627                                selected_text = None;
14628                            }
14629                        } else {
14630                            same_text_selected = false;
14631                            selected_text = None;
14632                        }
14633                    }
14634                }
14635            }
14636
14637            if only_carets {
14638                for selection in &mut selections {
14639                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14640                    selection.start = word_range.start;
14641                    selection.end = word_range.end;
14642                    selection.goal = SelectionGoal::None;
14643                    selection.reversed = false;
14644                    self.select_match_ranges(
14645                        selection.start..selection.end,
14646                        selection.reversed,
14647                        action.replace_newest,
14648                        Some(Autoscroll::newest()),
14649                        window,
14650                        cx,
14651                    );
14652                }
14653                if selections.len() == 1 {
14654                    let selection = selections
14655                        .last()
14656                        .expect("ensured that there's only one selection");
14657                    let query = buffer
14658                        .text_for_range(selection.start..selection.end)
14659                        .collect::<String>();
14660                    let is_empty = query.is_empty();
14661                    let select_state = SelectNextState {
14662                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14663                        wordwise: true,
14664                        done: is_empty,
14665                    };
14666                    self.select_prev_state = Some(select_state);
14667                } else {
14668                    self.select_prev_state = None;
14669                }
14670            } else if let Some(selected_text) = selected_text {
14671                self.select_prev_state = Some(SelectNextState {
14672                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14673                    wordwise: false,
14674                    done: false,
14675                });
14676                self.select_previous(action, window, cx)?;
14677            }
14678        }
14679        Ok(())
14680    }
14681
14682    pub fn find_next_match(
14683        &mut self,
14684        _: &FindNextMatch,
14685        window: &mut Window,
14686        cx: &mut Context<Self>,
14687    ) -> Result<()> {
14688        let selections = self.selections.disjoint_anchors_arc();
14689        match selections.first() {
14690            Some(first) if selections.len() >= 2 => {
14691                self.change_selections(Default::default(), window, cx, |s| {
14692                    s.select_ranges([first.range()]);
14693                });
14694            }
14695            _ => self.select_next(
14696                &SelectNext {
14697                    replace_newest: true,
14698                },
14699                window,
14700                cx,
14701            )?,
14702        }
14703        Ok(())
14704    }
14705
14706    pub fn find_previous_match(
14707        &mut self,
14708        _: &FindPreviousMatch,
14709        window: &mut Window,
14710        cx: &mut Context<Self>,
14711    ) -> Result<()> {
14712        let selections = self.selections.disjoint_anchors_arc();
14713        match selections.last() {
14714            Some(last) if selections.len() >= 2 => {
14715                self.change_selections(Default::default(), window, cx, |s| {
14716                    s.select_ranges([last.range()]);
14717                });
14718            }
14719            _ => self.select_previous(
14720                &SelectPrevious {
14721                    replace_newest: true,
14722                },
14723                window,
14724                cx,
14725            )?,
14726        }
14727        Ok(())
14728    }
14729
14730    pub fn toggle_comments(
14731        &mut self,
14732        action: &ToggleComments,
14733        window: &mut Window,
14734        cx: &mut Context<Self>,
14735    ) {
14736        if self.read_only(cx) {
14737            return;
14738        }
14739        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14740        let text_layout_details = &self.text_layout_details(window);
14741        self.transact(window, cx, |this, window, cx| {
14742            let mut selections = this
14743                .selections
14744                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14745            let mut edits = Vec::new();
14746            let mut selection_edit_ranges = Vec::new();
14747            let mut last_toggled_row = None;
14748            let snapshot = this.buffer.read(cx).read(cx);
14749            let empty_str: Arc<str> = Arc::default();
14750            let mut suffixes_inserted = Vec::new();
14751            let ignore_indent = action.ignore_indent;
14752
14753            fn comment_prefix_range(
14754                snapshot: &MultiBufferSnapshot,
14755                row: MultiBufferRow,
14756                comment_prefix: &str,
14757                comment_prefix_whitespace: &str,
14758                ignore_indent: bool,
14759            ) -> Range<Point> {
14760                let indent_size = if ignore_indent {
14761                    0
14762                } else {
14763                    snapshot.indent_size_for_line(row).len
14764                };
14765
14766                let start = Point::new(row.0, indent_size);
14767
14768                let mut line_bytes = snapshot
14769                    .bytes_in_range(start..snapshot.max_point())
14770                    .flatten()
14771                    .copied();
14772
14773                // If this line currently begins with the line comment prefix, then record
14774                // the range containing the prefix.
14775                if line_bytes
14776                    .by_ref()
14777                    .take(comment_prefix.len())
14778                    .eq(comment_prefix.bytes())
14779                {
14780                    // Include any whitespace that matches the comment prefix.
14781                    let matching_whitespace_len = line_bytes
14782                        .zip(comment_prefix_whitespace.bytes())
14783                        .take_while(|(a, b)| a == b)
14784                        .count() as u32;
14785                    let end = Point::new(
14786                        start.row,
14787                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14788                    );
14789                    start..end
14790                } else {
14791                    start..start
14792                }
14793            }
14794
14795            fn comment_suffix_range(
14796                snapshot: &MultiBufferSnapshot,
14797                row: MultiBufferRow,
14798                comment_suffix: &str,
14799                comment_suffix_has_leading_space: bool,
14800            ) -> Range<Point> {
14801                let end = Point::new(row.0, snapshot.line_len(row));
14802                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14803
14804                let mut line_end_bytes = snapshot
14805                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14806                    .flatten()
14807                    .copied();
14808
14809                let leading_space_len = if suffix_start_column > 0
14810                    && line_end_bytes.next() == Some(b' ')
14811                    && comment_suffix_has_leading_space
14812                {
14813                    1
14814                } else {
14815                    0
14816                };
14817
14818                // If this line currently begins with the line comment prefix, then record
14819                // the range containing the prefix.
14820                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14821                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14822                    start..end
14823                } else {
14824                    end..end
14825                }
14826            }
14827
14828            // TODO: Handle selections that cross excerpts
14829            for selection in &mut selections {
14830                let start_column = snapshot
14831                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14832                    .len;
14833                let language = if let Some(language) =
14834                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14835                {
14836                    language
14837                } else {
14838                    continue;
14839                };
14840
14841                selection_edit_ranges.clear();
14842
14843                // If multiple selections contain a given row, avoid processing that
14844                // row more than once.
14845                let mut start_row = MultiBufferRow(selection.start.row);
14846                if last_toggled_row == Some(start_row) {
14847                    start_row = start_row.next_row();
14848                }
14849                let end_row =
14850                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14851                        MultiBufferRow(selection.end.row - 1)
14852                    } else {
14853                        MultiBufferRow(selection.end.row)
14854                    };
14855                last_toggled_row = Some(end_row);
14856
14857                if start_row > end_row {
14858                    continue;
14859                }
14860
14861                // If the language has line comments, toggle those.
14862                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14863
14864                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14865                if ignore_indent {
14866                    full_comment_prefixes = full_comment_prefixes
14867                        .into_iter()
14868                        .map(|s| Arc::from(s.trim_end()))
14869                        .collect();
14870                }
14871
14872                if !full_comment_prefixes.is_empty() {
14873                    let first_prefix = full_comment_prefixes
14874                        .first()
14875                        .expect("prefixes is non-empty");
14876                    let prefix_trimmed_lengths = full_comment_prefixes
14877                        .iter()
14878                        .map(|p| p.trim_end_matches(' ').len())
14879                        .collect::<SmallVec<[usize; 4]>>();
14880
14881                    let mut all_selection_lines_are_comments = true;
14882
14883                    for row in start_row.0..=end_row.0 {
14884                        let row = MultiBufferRow(row);
14885                        if start_row < end_row && snapshot.is_line_blank(row) {
14886                            continue;
14887                        }
14888
14889                        let prefix_range = full_comment_prefixes
14890                            .iter()
14891                            .zip(prefix_trimmed_lengths.iter().copied())
14892                            .map(|(prefix, trimmed_prefix_len)| {
14893                                comment_prefix_range(
14894                                    snapshot.deref(),
14895                                    row,
14896                                    &prefix[..trimmed_prefix_len],
14897                                    &prefix[trimmed_prefix_len..],
14898                                    ignore_indent,
14899                                )
14900                            })
14901                            .max_by_key(|range| range.end.column - range.start.column)
14902                            .expect("prefixes is non-empty");
14903
14904                        if prefix_range.is_empty() {
14905                            all_selection_lines_are_comments = false;
14906                        }
14907
14908                        selection_edit_ranges.push(prefix_range);
14909                    }
14910
14911                    if all_selection_lines_are_comments {
14912                        edits.extend(
14913                            selection_edit_ranges
14914                                .iter()
14915                                .cloned()
14916                                .map(|range| (range, empty_str.clone())),
14917                        );
14918                    } else {
14919                        let min_column = selection_edit_ranges
14920                            .iter()
14921                            .map(|range| range.start.column)
14922                            .min()
14923                            .unwrap_or(0);
14924                        edits.extend(selection_edit_ranges.iter().map(|range| {
14925                            let position = Point::new(range.start.row, min_column);
14926                            (position..position, first_prefix.clone())
14927                        }));
14928                    }
14929                } else if let Some(BlockCommentConfig {
14930                    start: full_comment_prefix,
14931                    end: comment_suffix,
14932                    ..
14933                }) = language.block_comment()
14934                {
14935                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14936                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14937                    let prefix_range = comment_prefix_range(
14938                        snapshot.deref(),
14939                        start_row,
14940                        comment_prefix,
14941                        comment_prefix_whitespace,
14942                        ignore_indent,
14943                    );
14944                    let suffix_range = comment_suffix_range(
14945                        snapshot.deref(),
14946                        end_row,
14947                        comment_suffix.trim_start_matches(' '),
14948                        comment_suffix.starts_with(' '),
14949                    );
14950
14951                    if prefix_range.is_empty() || suffix_range.is_empty() {
14952                        edits.push((
14953                            prefix_range.start..prefix_range.start,
14954                            full_comment_prefix.clone(),
14955                        ));
14956                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14957                        suffixes_inserted.push((end_row, comment_suffix.len()));
14958                    } else {
14959                        edits.push((prefix_range, empty_str.clone()));
14960                        edits.push((suffix_range, empty_str.clone()));
14961                    }
14962                } else {
14963                    continue;
14964                }
14965            }
14966
14967            drop(snapshot);
14968            this.buffer.update(cx, |buffer, cx| {
14969                buffer.edit(edits, None, cx);
14970            });
14971
14972            // Adjust selections so that they end before any comment suffixes that
14973            // were inserted.
14974            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14975            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
14976            let snapshot = this.buffer.read(cx).read(cx);
14977            for selection in &mut selections {
14978                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14979                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14980                        Ordering::Less => {
14981                            suffixes_inserted.next();
14982                            continue;
14983                        }
14984                        Ordering::Greater => break,
14985                        Ordering::Equal => {
14986                            if selection.end.column == snapshot.line_len(row) {
14987                                if selection.is_empty() {
14988                                    selection.start.column -= suffix_len as u32;
14989                                }
14990                                selection.end.column -= suffix_len as u32;
14991                            }
14992                            break;
14993                        }
14994                    }
14995                }
14996            }
14997
14998            drop(snapshot);
14999            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15000
15001            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15002            let selections_on_single_row = selections.windows(2).all(|selections| {
15003                selections[0].start.row == selections[1].start.row
15004                    && selections[0].end.row == selections[1].end.row
15005                    && selections[0].start.row == selections[0].end.row
15006            });
15007            let selections_selecting = selections
15008                .iter()
15009                .any(|selection| selection.start != selection.end);
15010            let advance_downwards = action.advance_downwards
15011                && selections_on_single_row
15012                && !selections_selecting
15013                && !matches!(this.mode, EditorMode::SingleLine);
15014
15015            if advance_downwards {
15016                let snapshot = this.buffer.read(cx).snapshot(cx);
15017
15018                this.change_selections(Default::default(), window, cx, |s| {
15019                    s.move_cursors_with(|display_snapshot, display_point, _| {
15020                        let mut point = display_point.to_point(display_snapshot);
15021                        point.row += 1;
15022                        point = snapshot.clip_point(point, Bias::Left);
15023                        let display_point = point.to_display_point(display_snapshot);
15024                        let goal = SelectionGoal::HorizontalPosition(
15025                            display_snapshot
15026                                .x_for_display_point(display_point, text_layout_details)
15027                                .into(),
15028                        );
15029                        (display_point, goal)
15030                    })
15031                });
15032            }
15033        });
15034    }
15035
15036    pub fn select_enclosing_symbol(
15037        &mut self,
15038        _: &SelectEnclosingSymbol,
15039        window: &mut Window,
15040        cx: &mut Context<Self>,
15041    ) {
15042        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15043
15044        let buffer = self.buffer.read(cx).snapshot(cx);
15045        let old_selections = self
15046            .selections
15047            .all::<usize>(&self.display_snapshot(cx))
15048            .into_boxed_slice();
15049
15050        fn update_selection(
15051            selection: &Selection<usize>,
15052            buffer_snap: &MultiBufferSnapshot,
15053        ) -> Option<Selection<usize>> {
15054            let cursor = selection.head();
15055            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15056            for symbol in symbols.iter().rev() {
15057                let start = symbol.range.start.to_offset(buffer_snap);
15058                let end = symbol.range.end.to_offset(buffer_snap);
15059                let new_range = start..end;
15060                if start < selection.start || end > selection.end {
15061                    return Some(Selection {
15062                        id: selection.id,
15063                        start: new_range.start,
15064                        end: new_range.end,
15065                        goal: SelectionGoal::None,
15066                        reversed: selection.reversed,
15067                    });
15068                }
15069            }
15070            None
15071        }
15072
15073        let mut selected_larger_symbol = false;
15074        let new_selections = old_selections
15075            .iter()
15076            .map(|selection| match update_selection(selection, &buffer) {
15077                Some(new_selection) => {
15078                    if new_selection.range() != selection.range() {
15079                        selected_larger_symbol = true;
15080                    }
15081                    new_selection
15082                }
15083                None => selection.clone(),
15084            })
15085            .collect::<Vec<_>>();
15086
15087        if selected_larger_symbol {
15088            self.change_selections(Default::default(), window, cx, |s| {
15089                s.select(new_selections);
15090            });
15091        }
15092    }
15093
15094    pub fn select_larger_syntax_node(
15095        &mut self,
15096        _: &SelectLargerSyntaxNode,
15097        window: &mut Window,
15098        cx: &mut Context<Self>,
15099    ) {
15100        let Some(visible_row_count) = self.visible_row_count() else {
15101            return;
15102        };
15103        let old_selections: Box<[_]> = self
15104            .selections
15105            .all::<usize>(&self.display_snapshot(cx))
15106            .into();
15107        if old_selections.is_empty() {
15108            return;
15109        }
15110
15111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15112
15113        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15114        let buffer = self.buffer.read(cx).snapshot(cx);
15115
15116        let mut selected_larger_node = false;
15117        let mut new_selections = old_selections
15118            .iter()
15119            .map(|selection| {
15120                let old_range = selection.start..selection.end;
15121
15122                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15123                    // manually select word at selection
15124                    if ["string_content", "inline"].contains(&node.kind()) {
15125                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15126                        // ignore if word is already selected
15127                        if !word_range.is_empty() && old_range != word_range {
15128                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15129                            // only select word if start and end point belongs to same word
15130                            if word_range == last_word_range {
15131                                selected_larger_node = true;
15132                                return Selection {
15133                                    id: selection.id,
15134                                    start: word_range.start,
15135                                    end: word_range.end,
15136                                    goal: SelectionGoal::None,
15137                                    reversed: selection.reversed,
15138                                };
15139                            }
15140                        }
15141                    }
15142                }
15143
15144                let mut new_range = old_range.clone();
15145                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15146                    new_range = range;
15147                    if !node.is_named() {
15148                        continue;
15149                    }
15150                    if !display_map.intersects_fold(new_range.start)
15151                        && !display_map.intersects_fold(new_range.end)
15152                    {
15153                        break;
15154                    }
15155                }
15156
15157                selected_larger_node |= new_range != old_range;
15158                Selection {
15159                    id: selection.id,
15160                    start: new_range.start,
15161                    end: new_range.end,
15162                    goal: SelectionGoal::None,
15163                    reversed: selection.reversed,
15164                }
15165            })
15166            .collect::<Vec<_>>();
15167
15168        if !selected_larger_node {
15169            return; // don't put this call in the history
15170        }
15171
15172        // scroll based on transformation done to the last selection created by the user
15173        let (last_old, last_new) = old_selections
15174            .last()
15175            .zip(new_selections.last().cloned())
15176            .expect("old_selections isn't empty");
15177
15178        // revert selection
15179        let is_selection_reversed = {
15180            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15181            new_selections.last_mut().expect("checked above").reversed =
15182                should_newest_selection_be_reversed;
15183            should_newest_selection_be_reversed
15184        };
15185
15186        if selected_larger_node {
15187            self.select_syntax_node_history.disable_clearing = true;
15188            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15189                s.select(new_selections.clone());
15190            });
15191            self.select_syntax_node_history.disable_clearing = false;
15192        }
15193
15194        let start_row = last_new.start.to_display_point(&display_map).row().0;
15195        let end_row = last_new.end.to_display_point(&display_map).row().0;
15196        let selection_height = end_row - start_row + 1;
15197        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15198
15199        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15200        let scroll_behavior = if fits_on_the_screen {
15201            self.request_autoscroll(Autoscroll::fit(), cx);
15202            SelectSyntaxNodeScrollBehavior::FitSelection
15203        } else if is_selection_reversed {
15204            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15205            SelectSyntaxNodeScrollBehavior::CursorTop
15206        } else {
15207            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15208            SelectSyntaxNodeScrollBehavior::CursorBottom
15209        };
15210
15211        self.select_syntax_node_history.push((
15212            old_selections,
15213            scroll_behavior,
15214            is_selection_reversed,
15215        ));
15216    }
15217
15218    pub fn select_smaller_syntax_node(
15219        &mut self,
15220        _: &SelectSmallerSyntaxNode,
15221        window: &mut Window,
15222        cx: &mut Context<Self>,
15223    ) {
15224        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15225
15226        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15227            self.select_syntax_node_history.pop()
15228        {
15229            if let Some(selection) = selections.last_mut() {
15230                selection.reversed = is_selection_reversed;
15231            }
15232
15233            self.select_syntax_node_history.disable_clearing = true;
15234            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15235                s.select(selections.to_vec());
15236            });
15237            self.select_syntax_node_history.disable_clearing = false;
15238
15239            match scroll_behavior {
15240                SelectSyntaxNodeScrollBehavior::CursorTop => {
15241                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15242                }
15243                SelectSyntaxNodeScrollBehavior::FitSelection => {
15244                    self.request_autoscroll(Autoscroll::fit(), cx);
15245                }
15246                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15247                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15248                }
15249            }
15250        }
15251    }
15252
15253    pub fn unwrap_syntax_node(
15254        &mut self,
15255        _: &UnwrapSyntaxNode,
15256        window: &mut Window,
15257        cx: &mut Context<Self>,
15258    ) {
15259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15260
15261        let buffer = self.buffer.read(cx).snapshot(cx);
15262        let selections = self
15263            .selections
15264            .all::<usize>(&self.display_snapshot(cx))
15265            .into_iter()
15266            // subtracting the offset requires sorting
15267            .sorted_by_key(|i| i.start);
15268
15269        let full_edits = selections
15270            .into_iter()
15271            .filter_map(|selection| {
15272                let child = if selection.is_empty()
15273                    && let Some((_, ancestor_range)) =
15274                        buffer.syntax_ancestor(selection.start..selection.end)
15275                {
15276                    ancestor_range
15277                } else {
15278                    selection.range()
15279                };
15280
15281                let mut parent = child.clone();
15282                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15283                    parent = ancestor_range;
15284                    if parent.start < child.start || parent.end > child.end {
15285                        break;
15286                    }
15287                }
15288
15289                if parent == child {
15290                    return None;
15291                }
15292                let text = buffer.text_for_range(child).collect::<String>();
15293                Some((selection.id, parent, text))
15294            })
15295            .collect::<Vec<_>>();
15296        if full_edits.is_empty() {
15297            return;
15298        }
15299
15300        self.transact(window, cx, |this, window, cx| {
15301            this.buffer.update(cx, |buffer, cx| {
15302                buffer.edit(
15303                    full_edits
15304                        .iter()
15305                        .map(|(_, p, t)| (p.clone(), t.clone()))
15306                        .collect::<Vec<_>>(),
15307                    None,
15308                    cx,
15309                );
15310            });
15311            this.change_selections(Default::default(), window, cx, |s| {
15312                let mut offset = 0;
15313                let mut selections = vec![];
15314                for (id, parent, text) in full_edits {
15315                    let start = parent.start - offset;
15316                    offset += parent.len() - text.len();
15317                    selections.push(Selection {
15318                        id,
15319                        start,
15320                        end: start + text.len(),
15321                        reversed: false,
15322                        goal: Default::default(),
15323                    });
15324                }
15325                s.select(selections);
15326            });
15327        });
15328    }
15329
15330    pub fn select_next_syntax_node(
15331        &mut self,
15332        _: &SelectNextSyntaxNode,
15333        window: &mut Window,
15334        cx: &mut Context<Self>,
15335    ) {
15336        let old_selections: Box<[_]> = self
15337            .selections
15338            .all::<usize>(&self.display_snapshot(cx))
15339            .into();
15340        if old_selections.is_empty() {
15341            return;
15342        }
15343
15344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15345
15346        let buffer = self.buffer.read(cx).snapshot(cx);
15347        let mut selected_sibling = false;
15348
15349        let new_selections = old_selections
15350            .iter()
15351            .map(|selection| {
15352                let old_range = selection.start..selection.end;
15353
15354                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15355                    let new_range = node.byte_range();
15356                    selected_sibling = true;
15357                    Selection {
15358                        id: selection.id,
15359                        start: new_range.start,
15360                        end: new_range.end,
15361                        goal: SelectionGoal::None,
15362                        reversed: selection.reversed,
15363                    }
15364                } else {
15365                    selection.clone()
15366                }
15367            })
15368            .collect::<Vec<_>>();
15369
15370        if selected_sibling {
15371            self.change_selections(
15372                SelectionEffects::scroll(Autoscroll::fit()),
15373                window,
15374                cx,
15375                |s| {
15376                    s.select(new_selections);
15377                },
15378            );
15379        }
15380    }
15381
15382    pub fn select_prev_syntax_node(
15383        &mut self,
15384        _: &SelectPreviousSyntaxNode,
15385        window: &mut Window,
15386        cx: &mut Context<Self>,
15387    ) {
15388        let old_selections: Box<[_]> = self
15389            .selections
15390            .all::<usize>(&self.display_snapshot(cx))
15391            .into();
15392        if old_selections.is_empty() {
15393            return;
15394        }
15395
15396        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15397
15398        let buffer = self.buffer.read(cx).snapshot(cx);
15399        let mut selected_sibling = false;
15400
15401        let new_selections = old_selections
15402            .iter()
15403            .map(|selection| {
15404                let old_range = selection.start..selection.end;
15405
15406                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15407                    let new_range = node.byte_range();
15408                    selected_sibling = true;
15409                    Selection {
15410                        id: selection.id,
15411                        start: new_range.start,
15412                        end: new_range.end,
15413                        goal: SelectionGoal::None,
15414                        reversed: selection.reversed,
15415                    }
15416                } else {
15417                    selection.clone()
15418                }
15419            })
15420            .collect::<Vec<_>>();
15421
15422        if selected_sibling {
15423            self.change_selections(
15424                SelectionEffects::scroll(Autoscroll::fit()),
15425                window,
15426                cx,
15427                |s| {
15428                    s.select(new_selections);
15429                },
15430            );
15431        }
15432    }
15433
15434    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15435        if !EditorSettings::get_global(cx).gutter.runnables {
15436            self.clear_tasks();
15437            return Task::ready(());
15438        }
15439        let project = self.project().map(Entity::downgrade);
15440        let task_sources = self.lsp_task_sources(cx);
15441        let multi_buffer = self.buffer.downgrade();
15442        cx.spawn_in(window, async move |editor, cx| {
15443            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15444            let Some(project) = project.and_then(|p| p.upgrade()) else {
15445                return;
15446            };
15447            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15448                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15449            }) else {
15450                return;
15451            };
15452
15453            let hide_runnables = project
15454                .update(cx, |project, _| project.is_via_collab())
15455                .unwrap_or(true);
15456            if hide_runnables {
15457                return;
15458            }
15459            let new_rows =
15460                cx.background_spawn({
15461                    let snapshot = display_snapshot.clone();
15462                    async move {
15463                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15464                    }
15465                })
15466                    .await;
15467            let Ok(lsp_tasks) =
15468                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15469            else {
15470                return;
15471            };
15472            let lsp_tasks = lsp_tasks.await;
15473
15474            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15475                lsp_tasks
15476                    .into_iter()
15477                    .flat_map(|(kind, tasks)| {
15478                        tasks.into_iter().filter_map(move |(location, task)| {
15479                            Some((kind.clone(), location?, task))
15480                        })
15481                    })
15482                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15483                        let buffer = location.target.buffer;
15484                        let buffer_snapshot = buffer.read(cx).snapshot();
15485                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15486                            |(excerpt_id, snapshot, _)| {
15487                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15488                                    display_snapshot
15489                                        .buffer_snapshot()
15490                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15491                                } else {
15492                                    None
15493                                }
15494                            },
15495                        );
15496                        if let Some(offset) = offset {
15497                            let task_buffer_range =
15498                                location.target.range.to_point(&buffer_snapshot);
15499                            let context_buffer_range =
15500                                task_buffer_range.to_offset(&buffer_snapshot);
15501                            let context_range = BufferOffset(context_buffer_range.start)
15502                                ..BufferOffset(context_buffer_range.end);
15503
15504                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15505                                .or_insert_with(|| RunnableTasks {
15506                                    templates: Vec::new(),
15507                                    offset,
15508                                    column: task_buffer_range.start.column,
15509                                    extra_variables: HashMap::default(),
15510                                    context_range,
15511                                })
15512                                .templates
15513                                .push((kind, task.original_task().clone()));
15514                        }
15515
15516                        acc
15517                    })
15518            }) else {
15519                return;
15520            };
15521
15522            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15523                buffer.language_settings(cx).tasks.prefer_lsp
15524            }) else {
15525                return;
15526            };
15527
15528            let rows = Self::runnable_rows(
15529                project,
15530                display_snapshot,
15531                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15532                new_rows,
15533                cx.clone(),
15534            )
15535            .await;
15536            editor
15537                .update(cx, |editor, _| {
15538                    editor.clear_tasks();
15539                    for (key, mut value) in rows {
15540                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15541                            value.templates.extend(lsp_tasks.templates);
15542                        }
15543
15544                        editor.insert_tasks(key, value);
15545                    }
15546                    for (key, value) in lsp_tasks_by_rows {
15547                        editor.insert_tasks(key, value);
15548                    }
15549                })
15550                .ok();
15551        })
15552    }
15553    fn fetch_runnable_ranges(
15554        snapshot: &DisplaySnapshot,
15555        range: Range<Anchor>,
15556    ) -> Vec<language::RunnableRange> {
15557        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15558    }
15559
15560    fn runnable_rows(
15561        project: Entity<Project>,
15562        snapshot: DisplaySnapshot,
15563        prefer_lsp: bool,
15564        runnable_ranges: Vec<RunnableRange>,
15565        cx: AsyncWindowContext,
15566    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15567        cx.spawn(async move |cx| {
15568            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15569            for mut runnable in runnable_ranges {
15570                let Some(tasks) = cx
15571                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15572                    .ok()
15573                else {
15574                    continue;
15575                };
15576                let mut tasks = tasks.await;
15577
15578                if prefer_lsp {
15579                    tasks.retain(|(task_kind, _)| {
15580                        !matches!(task_kind, TaskSourceKind::Language { .. })
15581                    });
15582                }
15583                if tasks.is_empty() {
15584                    continue;
15585                }
15586
15587                let point = runnable
15588                    .run_range
15589                    .start
15590                    .to_point(&snapshot.buffer_snapshot());
15591                let Some(row) = snapshot
15592                    .buffer_snapshot()
15593                    .buffer_line_for_row(MultiBufferRow(point.row))
15594                    .map(|(_, range)| range.start.row)
15595                else {
15596                    continue;
15597                };
15598
15599                let context_range =
15600                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15601                runnable_rows.push((
15602                    (runnable.buffer_id, row),
15603                    RunnableTasks {
15604                        templates: tasks,
15605                        offset: snapshot
15606                            .buffer_snapshot()
15607                            .anchor_before(runnable.run_range.start),
15608                        context_range,
15609                        column: point.column,
15610                        extra_variables: runnable.extra_captures,
15611                    },
15612                ));
15613            }
15614            runnable_rows
15615        })
15616    }
15617
15618    fn templates_with_tags(
15619        project: &Entity<Project>,
15620        runnable: &mut Runnable,
15621        cx: &mut App,
15622    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15623        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15624            let (worktree_id, file) = project
15625                .buffer_for_id(runnable.buffer, cx)
15626                .and_then(|buffer| buffer.read(cx).file())
15627                .map(|file| (file.worktree_id(cx), file.clone()))
15628                .unzip();
15629
15630            (
15631                project.task_store().read(cx).task_inventory().cloned(),
15632                worktree_id,
15633                file,
15634            )
15635        });
15636
15637        let tags = mem::take(&mut runnable.tags);
15638        let language = runnable.language.clone();
15639        cx.spawn(async move |cx| {
15640            let mut templates_with_tags = Vec::new();
15641            if let Some(inventory) = inventory {
15642                for RunnableTag(tag) in tags {
15643                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15644                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15645                    }) else {
15646                        return templates_with_tags;
15647                    };
15648                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15649                        move |(_, template)| {
15650                            template.tags.iter().any(|source_tag| source_tag == &tag)
15651                        },
15652                    ));
15653                }
15654            }
15655            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15656
15657            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15658                // Strongest source wins; if we have worktree tag binding, prefer that to
15659                // global and language bindings;
15660                // if we have a global binding, prefer that to language binding.
15661                let first_mismatch = templates_with_tags
15662                    .iter()
15663                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15664                if let Some(index) = first_mismatch {
15665                    templates_with_tags.truncate(index);
15666                }
15667            }
15668
15669            templates_with_tags
15670        })
15671    }
15672
15673    pub fn move_to_enclosing_bracket(
15674        &mut self,
15675        _: &MoveToEnclosingBracket,
15676        window: &mut Window,
15677        cx: &mut Context<Self>,
15678    ) {
15679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15680        self.change_selections(Default::default(), window, cx, |s| {
15681            s.move_offsets_with(|snapshot, selection| {
15682                let Some(enclosing_bracket_ranges) =
15683                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15684                else {
15685                    return;
15686                };
15687
15688                let mut best_length = usize::MAX;
15689                let mut best_inside = false;
15690                let mut best_in_bracket_range = false;
15691                let mut best_destination = None;
15692                for (open, close) in enclosing_bracket_ranges {
15693                    let close = close.to_inclusive();
15694                    let length = close.end() - open.start;
15695                    let inside = selection.start >= open.end && selection.end <= *close.start();
15696                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15697                        || close.contains(&selection.head());
15698
15699                    // If best is next to a bracket and current isn't, skip
15700                    if !in_bracket_range && best_in_bracket_range {
15701                        continue;
15702                    }
15703
15704                    // Prefer smaller lengths unless best is inside and current isn't
15705                    if length > best_length && (best_inside || !inside) {
15706                        continue;
15707                    }
15708
15709                    best_length = length;
15710                    best_inside = inside;
15711                    best_in_bracket_range = in_bracket_range;
15712                    best_destination = Some(
15713                        if close.contains(&selection.start) && close.contains(&selection.end) {
15714                            if inside { open.end } else { open.start }
15715                        } else if inside {
15716                            *close.start()
15717                        } else {
15718                            *close.end()
15719                        },
15720                    );
15721                }
15722
15723                if let Some(destination) = best_destination {
15724                    selection.collapse_to(destination, SelectionGoal::None);
15725                }
15726            })
15727        });
15728    }
15729
15730    pub fn undo_selection(
15731        &mut self,
15732        _: &UndoSelection,
15733        window: &mut Window,
15734        cx: &mut Context<Self>,
15735    ) {
15736        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15737        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15738            self.selection_history.mode = SelectionHistoryMode::Undoing;
15739            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15740                this.end_selection(window, cx);
15741                this.change_selections(
15742                    SelectionEffects::scroll(Autoscroll::newest()),
15743                    window,
15744                    cx,
15745                    |s| s.select_anchors(entry.selections.to_vec()),
15746                );
15747            });
15748            self.selection_history.mode = SelectionHistoryMode::Normal;
15749
15750            self.select_next_state = entry.select_next_state;
15751            self.select_prev_state = entry.select_prev_state;
15752            self.add_selections_state = entry.add_selections_state;
15753        }
15754    }
15755
15756    pub fn redo_selection(
15757        &mut self,
15758        _: &RedoSelection,
15759        window: &mut Window,
15760        cx: &mut Context<Self>,
15761    ) {
15762        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15763        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15764            self.selection_history.mode = SelectionHistoryMode::Redoing;
15765            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15766                this.end_selection(window, cx);
15767                this.change_selections(
15768                    SelectionEffects::scroll(Autoscroll::newest()),
15769                    window,
15770                    cx,
15771                    |s| s.select_anchors(entry.selections.to_vec()),
15772                );
15773            });
15774            self.selection_history.mode = SelectionHistoryMode::Normal;
15775
15776            self.select_next_state = entry.select_next_state;
15777            self.select_prev_state = entry.select_prev_state;
15778            self.add_selections_state = entry.add_selections_state;
15779        }
15780    }
15781
15782    pub fn expand_excerpts(
15783        &mut self,
15784        action: &ExpandExcerpts,
15785        _: &mut Window,
15786        cx: &mut Context<Self>,
15787    ) {
15788        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15789    }
15790
15791    pub fn expand_excerpts_down(
15792        &mut self,
15793        action: &ExpandExcerptsDown,
15794        _: &mut Window,
15795        cx: &mut Context<Self>,
15796    ) {
15797        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15798    }
15799
15800    pub fn expand_excerpts_up(
15801        &mut self,
15802        action: &ExpandExcerptsUp,
15803        _: &mut Window,
15804        cx: &mut Context<Self>,
15805    ) {
15806        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15807    }
15808
15809    pub fn expand_excerpts_for_direction(
15810        &mut self,
15811        lines: u32,
15812        direction: ExpandExcerptDirection,
15813
15814        cx: &mut Context<Self>,
15815    ) {
15816        let selections = self.selections.disjoint_anchors_arc();
15817
15818        let lines = if lines == 0 {
15819            EditorSettings::get_global(cx).expand_excerpt_lines
15820        } else {
15821            lines
15822        };
15823
15824        self.buffer.update(cx, |buffer, cx| {
15825            let snapshot = buffer.snapshot(cx);
15826            let mut excerpt_ids = selections
15827                .iter()
15828                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15829                .collect::<Vec<_>>();
15830            excerpt_ids.sort();
15831            excerpt_ids.dedup();
15832            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15833        })
15834    }
15835
15836    pub fn expand_excerpt(
15837        &mut self,
15838        excerpt: ExcerptId,
15839        direction: ExpandExcerptDirection,
15840        window: &mut Window,
15841        cx: &mut Context<Self>,
15842    ) {
15843        let current_scroll_position = self.scroll_position(cx);
15844        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15845        let mut should_scroll_up = false;
15846
15847        if direction == ExpandExcerptDirection::Down {
15848            let multi_buffer = self.buffer.read(cx);
15849            let snapshot = multi_buffer.snapshot(cx);
15850            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15851                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15852                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15853            {
15854                let buffer_snapshot = buffer.read(cx).snapshot();
15855                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15856                let last_row = buffer_snapshot.max_point().row;
15857                let lines_below = last_row.saturating_sub(excerpt_end_row);
15858                should_scroll_up = lines_below >= lines_to_expand;
15859            }
15860        }
15861
15862        self.buffer.update(cx, |buffer, cx| {
15863            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15864        });
15865
15866        if should_scroll_up {
15867            let new_scroll_position =
15868                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15869            self.set_scroll_position(new_scroll_position, window, cx);
15870        }
15871    }
15872
15873    pub fn go_to_singleton_buffer_point(
15874        &mut self,
15875        point: Point,
15876        window: &mut Window,
15877        cx: &mut Context<Self>,
15878    ) {
15879        self.go_to_singleton_buffer_range(point..point, window, cx);
15880    }
15881
15882    pub fn go_to_singleton_buffer_range(
15883        &mut self,
15884        range: Range<Point>,
15885        window: &mut Window,
15886        cx: &mut Context<Self>,
15887    ) {
15888        let multibuffer = self.buffer().read(cx);
15889        let Some(buffer) = multibuffer.as_singleton() else {
15890            return;
15891        };
15892        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15893            return;
15894        };
15895        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15896            return;
15897        };
15898        self.change_selections(
15899            SelectionEffects::default().nav_history(true),
15900            window,
15901            cx,
15902            |s| s.select_anchor_ranges([start..end]),
15903        );
15904    }
15905
15906    pub fn go_to_diagnostic(
15907        &mut self,
15908        action: &GoToDiagnostic,
15909        window: &mut Window,
15910        cx: &mut Context<Self>,
15911    ) {
15912        if !self.diagnostics_enabled() {
15913            return;
15914        }
15915        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15916        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15917    }
15918
15919    pub fn go_to_prev_diagnostic(
15920        &mut self,
15921        action: &GoToPreviousDiagnostic,
15922        window: &mut Window,
15923        cx: &mut Context<Self>,
15924    ) {
15925        if !self.diagnostics_enabled() {
15926            return;
15927        }
15928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15929        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15930    }
15931
15932    pub fn go_to_diagnostic_impl(
15933        &mut self,
15934        direction: Direction,
15935        severity: GoToDiagnosticSeverityFilter,
15936        window: &mut Window,
15937        cx: &mut Context<Self>,
15938    ) {
15939        let buffer = self.buffer.read(cx).snapshot(cx);
15940        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
15941
15942        let mut active_group_id = None;
15943        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15944            && active_group.active_range.start.to_offset(&buffer) == selection.start
15945        {
15946            active_group_id = Some(active_group.group_id);
15947        }
15948
15949        fn filtered<'a>(
15950            snapshot: EditorSnapshot,
15951            severity: GoToDiagnosticSeverityFilter,
15952            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
15953        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
15954            diagnostics
15955                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15956                .filter(|entry| entry.range.start != entry.range.end)
15957                .filter(|entry| !entry.diagnostic.is_unnecessary)
15958                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15959        }
15960
15961        let snapshot = self.snapshot(window, cx);
15962        let before = filtered(
15963            snapshot.clone(),
15964            severity,
15965            buffer
15966                .diagnostics_in_range(0..selection.start)
15967                .filter(|entry| entry.range.start <= selection.start),
15968        );
15969        let after = filtered(
15970            snapshot,
15971            severity,
15972            buffer
15973                .diagnostics_in_range(selection.start..buffer.len())
15974                .filter(|entry| entry.range.start >= selection.start),
15975        );
15976
15977        let mut found: Option<DiagnosticEntryRef<usize>> = None;
15978        if direction == Direction::Prev {
15979            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15980            {
15981                for diagnostic in prev_diagnostics.into_iter().rev() {
15982                    if diagnostic.range.start != selection.start
15983                        || active_group_id
15984                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15985                    {
15986                        found = Some(diagnostic);
15987                        break 'outer;
15988                    }
15989                }
15990            }
15991        } else {
15992            for diagnostic in after.chain(before) {
15993                if diagnostic.range.start != selection.start
15994                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15995                {
15996                    found = Some(diagnostic);
15997                    break;
15998                }
15999            }
16000        }
16001        let Some(next_diagnostic) = found else {
16002            return;
16003        };
16004
16005        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16006        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16007            return;
16008        };
16009        self.change_selections(Default::default(), window, cx, |s| {
16010            s.select_ranges(vec![
16011                next_diagnostic.range.start..next_diagnostic.range.start,
16012            ])
16013        });
16014        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16015        self.refresh_edit_prediction(false, true, window, cx);
16016    }
16017
16018    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16019        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16020        let snapshot = self.snapshot(window, cx);
16021        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16022        self.go_to_hunk_before_or_after_position(
16023            &snapshot,
16024            selection.head(),
16025            Direction::Next,
16026            window,
16027            cx,
16028        );
16029    }
16030
16031    pub fn go_to_hunk_before_or_after_position(
16032        &mut self,
16033        snapshot: &EditorSnapshot,
16034        position: Point,
16035        direction: Direction,
16036        window: &mut Window,
16037        cx: &mut Context<Editor>,
16038    ) {
16039        let row = if direction == Direction::Next {
16040            self.hunk_after_position(snapshot, position)
16041                .map(|hunk| hunk.row_range.start)
16042        } else {
16043            self.hunk_before_position(snapshot, position)
16044        };
16045
16046        if let Some(row) = row {
16047            let destination = Point::new(row.0, 0);
16048            let autoscroll = Autoscroll::center();
16049
16050            self.unfold_ranges(&[destination..destination], false, false, cx);
16051            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16052                s.select_ranges([destination..destination]);
16053            });
16054        }
16055    }
16056
16057    fn hunk_after_position(
16058        &mut self,
16059        snapshot: &EditorSnapshot,
16060        position: Point,
16061    ) -> Option<MultiBufferDiffHunk> {
16062        snapshot
16063            .buffer_snapshot()
16064            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16065            .find(|hunk| hunk.row_range.start.0 > position.row)
16066            .or_else(|| {
16067                snapshot
16068                    .buffer_snapshot()
16069                    .diff_hunks_in_range(Point::zero()..position)
16070                    .find(|hunk| hunk.row_range.end.0 < position.row)
16071            })
16072    }
16073
16074    fn go_to_prev_hunk(
16075        &mut self,
16076        _: &GoToPreviousHunk,
16077        window: &mut Window,
16078        cx: &mut Context<Self>,
16079    ) {
16080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16081        let snapshot = self.snapshot(window, cx);
16082        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16083        self.go_to_hunk_before_or_after_position(
16084            &snapshot,
16085            selection.head(),
16086            Direction::Prev,
16087            window,
16088            cx,
16089        );
16090    }
16091
16092    fn hunk_before_position(
16093        &mut self,
16094        snapshot: &EditorSnapshot,
16095        position: Point,
16096    ) -> Option<MultiBufferRow> {
16097        snapshot
16098            .buffer_snapshot()
16099            .diff_hunk_before(position)
16100            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16101    }
16102
16103    fn go_to_next_change(
16104        &mut self,
16105        _: &GoToNextChange,
16106        window: &mut Window,
16107        cx: &mut Context<Self>,
16108    ) {
16109        if let Some(selections) = self
16110            .change_list
16111            .next_change(1, Direction::Next)
16112            .map(|s| s.to_vec())
16113        {
16114            self.change_selections(Default::default(), window, cx, |s| {
16115                let map = s.display_map();
16116                s.select_display_ranges(selections.iter().map(|a| {
16117                    let point = a.to_display_point(&map);
16118                    point..point
16119                }))
16120            })
16121        }
16122    }
16123
16124    fn go_to_previous_change(
16125        &mut self,
16126        _: &GoToPreviousChange,
16127        window: &mut Window,
16128        cx: &mut Context<Self>,
16129    ) {
16130        if let Some(selections) = self
16131            .change_list
16132            .next_change(1, Direction::Prev)
16133            .map(|s| s.to_vec())
16134        {
16135            self.change_selections(Default::default(), window, cx, |s| {
16136                let map = s.display_map();
16137                s.select_display_ranges(selections.iter().map(|a| {
16138                    let point = a.to_display_point(&map);
16139                    point..point
16140                }))
16141            })
16142        }
16143    }
16144
16145    pub fn go_to_next_document_highlight(
16146        &mut self,
16147        _: &GoToNextDocumentHighlight,
16148        window: &mut Window,
16149        cx: &mut Context<Self>,
16150    ) {
16151        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16152    }
16153
16154    pub fn go_to_prev_document_highlight(
16155        &mut self,
16156        _: &GoToPreviousDocumentHighlight,
16157        window: &mut Window,
16158        cx: &mut Context<Self>,
16159    ) {
16160        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16161    }
16162
16163    pub fn go_to_document_highlight_before_or_after_position(
16164        &mut self,
16165        direction: Direction,
16166        window: &mut Window,
16167        cx: &mut Context<Editor>,
16168    ) {
16169        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16170        let snapshot = self.snapshot(window, cx);
16171        let buffer = &snapshot.buffer_snapshot();
16172        let position = self
16173            .selections
16174            .newest::<Point>(&snapshot.display_snapshot)
16175            .head();
16176        let anchor_position = buffer.anchor_after(position);
16177
16178        // Get all document highlights (both read and write)
16179        let mut all_highlights = Vec::new();
16180
16181        if let Some((_, read_highlights)) = self
16182            .background_highlights
16183            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16184        {
16185            all_highlights.extend(read_highlights.iter());
16186        }
16187
16188        if let Some((_, write_highlights)) = self
16189            .background_highlights
16190            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16191        {
16192            all_highlights.extend(write_highlights.iter());
16193        }
16194
16195        if all_highlights.is_empty() {
16196            return;
16197        }
16198
16199        // Sort highlights by position
16200        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16201
16202        let target_highlight = match direction {
16203            Direction::Next => {
16204                // Find the first highlight after the current position
16205                all_highlights
16206                    .iter()
16207                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16208            }
16209            Direction::Prev => {
16210                // Find the last highlight before the current position
16211                all_highlights
16212                    .iter()
16213                    .rev()
16214                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16215            }
16216        };
16217
16218        if let Some(highlight) = target_highlight {
16219            let destination = highlight.start.to_point(buffer);
16220            let autoscroll = Autoscroll::center();
16221
16222            self.unfold_ranges(&[destination..destination], false, false, cx);
16223            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16224                s.select_ranges([destination..destination]);
16225            });
16226        }
16227    }
16228
16229    fn go_to_line<T: 'static>(
16230        &mut self,
16231        position: Anchor,
16232        highlight_color: Option<Hsla>,
16233        window: &mut Window,
16234        cx: &mut Context<Self>,
16235    ) {
16236        let snapshot = self.snapshot(window, cx).display_snapshot;
16237        let position = position.to_point(&snapshot.buffer_snapshot());
16238        let start = snapshot
16239            .buffer_snapshot()
16240            .clip_point(Point::new(position.row, 0), Bias::Left);
16241        let end = start + Point::new(1, 0);
16242        let start = snapshot.buffer_snapshot().anchor_before(start);
16243        let end = snapshot.buffer_snapshot().anchor_before(end);
16244
16245        self.highlight_rows::<T>(
16246            start..end,
16247            highlight_color
16248                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16249            Default::default(),
16250            cx,
16251        );
16252
16253        if self.buffer.read(cx).is_singleton() {
16254            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16255        }
16256    }
16257
16258    pub fn go_to_definition(
16259        &mut self,
16260        _: &GoToDefinition,
16261        window: &mut Window,
16262        cx: &mut Context<Self>,
16263    ) -> Task<Result<Navigated>> {
16264        let definition =
16265            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16266        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16267        cx.spawn_in(window, async move |editor, cx| {
16268            if definition.await? == Navigated::Yes {
16269                return Ok(Navigated::Yes);
16270            }
16271            match fallback_strategy {
16272                GoToDefinitionFallback::None => Ok(Navigated::No),
16273                GoToDefinitionFallback::FindAllReferences => {
16274                    match editor.update_in(cx, |editor, window, cx| {
16275                        editor.find_all_references(&FindAllReferences, window, cx)
16276                    })? {
16277                        Some(references) => references.await,
16278                        None => Ok(Navigated::No),
16279                    }
16280                }
16281            }
16282        })
16283    }
16284
16285    pub fn go_to_declaration(
16286        &mut self,
16287        _: &GoToDeclaration,
16288        window: &mut Window,
16289        cx: &mut Context<Self>,
16290    ) -> Task<Result<Navigated>> {
16291        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16292    }
16293
16294    pub fn go_to_declaration_split(
16295        &mut self,
16296        _: &GoToDeclaration,
16297        window: &mut Window,
16298        cx: &mut Context<Self>,
16299    ) -> Task<Result<Navigated>> {
16300        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16301    }
16302
16303    pub fn go_to_implementation(
16304        &mut self,
16305        _: &GoToImplementation,
16306        window: &mut Window,
16307        cx: &mut Context<Self>,
16308    ) -> Task<Result<Navigated>> {
16309        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16310    }
16311
16312    pub fn go_to_implementation_split(
16313        &mut self,
16314        _: &GoToImplementationSplit,
16315        window: &mut Window,
16316        cx: &mut Context<Self>,
16317    ) -> Task<Result<Navigated>> {
16318        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16319    }
16320
16321    pub fn go_to_type_definition(
16322        &mut self,
16323        _: &GoToTypeDefinition,
16324        window: &mut Window,
16325        cx: &mut Context<Self>,
16326    ) -> Task<Result<Navigated>> {
16327        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16328    }
16329
16330    pub fn go_to_definition_split(
16331        &mut self,
16332        _: &GoToDefinitionSplit,
16333        window: &mut Window,
16334        cx: &mut Context<Self>,
16335    ) -> Task<Result<Navigated>> {
16336        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16337    }
16338
16339    pub fn go_to_type_definition_split(
16340        &mut self,
16341        _: &GoToTypeDefinitionSplit,
16342        window: &mut Window,
16343        cx: &mut Context<Self>,
16344    ) -> Task<Result<Navigated>> {
16345        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16346    }
16347
16348    fn go_to_definition_of_kind(
16349        &mut self,
16350        kind: GotoDefinitionKind,
16351        split: bool,
16352        window: &mut Window,
16353        cx: &mut Context<Self>,
16354    ) -> Task<Result<Navigated>> {
16355        let Some(provider) = self.semantics_provider.clone() else {
16356            return Task::ready(Ok(Navigated::No));
16357        };
16358        let head = self
16359            .selections
16360            .newest::<usize>(&self.display_snapshot(cx))
16361            .head();
16362        let buffer = self.buffer.read(cx);
16363        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16364            return Task::ready(Ok(Navigated::No));
16365        };
16366        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16367            return Task::ready(Ok(Navigated::No));
16368        };
16369
16370        cx.spawn_in(window, async move |editor, cx| {
16371            let Some(definitions) = definitions.await? else {
16372                return Ok(Navigated::No);
16373            };
16374            let navigated = editor
16375                .update_in(cx, |editor, window, cx| {
16376                    editor.navigate_to_hover_links(
16377                        Some(kind),
16378                        definitions
16379                            .into_iter()
16380                            .filter(|location| {
16381                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16382                            })
16383                            .map(HoverLink::Text)
16384                            .collect::<Vec<_>>(),
16385                        split,
16386                        window,
16387                        cx,
16388                    )
16389                })?
16390                .await?;
16391            anyhow::Ok(navigated)
16392        })
16393    }
16394
16395    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16396        let selection = self.selections.newest_anchor();
16397        let head = selection.head();
16398        let tail = selection.tail();
16399
16400        let Some((buffer, start_position)) =
16401            self.buffer.read(cx).text_anchor_for_position(head, cx)
16402        else {
16403            return;
16404        };
16405
16406        let end_position = if head != tail {
16407            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16408                return;
16409            };
16410            Some(pos)
16411        } else {
16412            None
16413        };
16414
16415        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16416            let url = if let Some(end_pos) = end_position {
16417                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16418            } else {
16419                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16420            };
16421
16422            if let Some(url) = url {
16423                cx.update(|window, cx| {
16424                    if parse_zed_link(&url, cx).is_some() {
16425                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16426                    } else {
16427                        cx.open_url(&url);
16428                    }
16429                })?;
16430            }
16431
16432            anyhow::Ok(())
16433        });
16434
16435        url_finder.detach();
16436    }
16437
16438    pub fn open_selected_filename(
16439        &mut self,
16440        _: &OpenSelectedFilename,
16441        window: &mut Window,
16442        cx: &mut Context<Self>,
16443    ) {
16444        let Some(workspace) = self.workspace() else {
16445            return;
16446        };
16447
16448        let position = self.selections.newest_anchor().head();
16449
16450        let Some((buffer, buffer_position)) =
16451            self.buffer.read(cx).text_anchor_for_position(position, cx)
16452        else {
16453            return;
16454        };
16455
16456        let project = self.project.clone();
16457
16458        cx.spawn_in(window, async move |_, cx| {
16459            let result = find_file(&buffer, project, buffer_position, cx).await;
16460
16461            if let Some((_, path)) = result {
16462                workspace
16463                    .update_in(cx, |workspace, window, cx| {
16464                        workspace.open_resolved_path(path, window, cx)
16465                    })?
16466                    .await?;
16467            }
16468            anyhow::Ok(())
16469        })
16470        .detach();
16471    }
16472
16473    pub(crate) fn navigate_to_hover_links(
16474        &mut self,
16475        kind: Option<GotoDefinitionKind>,
16476        definitions: Vec<HoverLink>,
16477        split: bool,
16478        window: &mut Window,
16479        cx: &mut Context<Editor>,
16480    ) -> Task<Result<Navigated>> {
16481        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16482        let mut first_url_or_file = None;
16483        let definitions: Vec<_> = definitions
16484            .into_iter()
16485            .filter_map(|def| match def {
16486                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16487                HoverLink::InlayHint(lsp_location, server_id) => {
16488                    let computation =
16489                        self.compute_target_location(lsp_location, server_id, window, cx);
16490                    Some(cx.background_spawn(computation))
16491                }
16492                HoverLink::Url(url) => {
16493                    first_url_or_file = Some(Either::Left(url));
16494                    None
16495                }
16496                HoverLink::File(path) => {
16497                    first_url_or_file = Some(Either::Right(path));
16498                    None
16499                }
16500            })
16501            .collect();
16502
16503        let workspace = self.workspace();
16504
16505        cx.spawn_in(window, async move |editor, cx| {
16506            let locations: Vec<Location> = future::join_all(definitions)
16507                .await
16508                .into_iter()
16509                .filter_map(|location| location.transpose())
16510                .collect::<Result<_>>()
16511                .context("location tasks")?;
16512            let mut locations = cx.update(|_, cx| {
16513                locations
16514                    .into_iter()
16515                    .map(|location| {
16516                        let buffer = location.buffer.read(cx);
16517                        (location.buffer, location.range.to_point(buffer))
16518                    })
16519                    .into_group_map()
16520            })?;
16521            let mut num_locations = 0;
16522            for ranges in locations.values_mut() {
16523                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16524                ranges.dedup();
16525                num_locations += ranges.len();
16526            }
16527
16528            if num_locations > 1 {
16529                let Some(workspace) = workspace else {
16530                    return Ok(Navigated::No);
16531                };
16532
16533                let tab_kind = match kind {
16534                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16535                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16536                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16537                    Some(GotoDefinitionKind::Type) => "Types",
16538                };
16539                let title = editor
16540                    .update_in(cx, |_, _, cx| {
16541                        let target = locations
16542                            .iter()
16543                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16544                            .map(|(buffer, location)| {
16545                                buffer
16546                                    .read(cx)
16547                                    .text_for_range(location.clone())
16548                                    .collect::<String>()
16549                            })
16550                            .filter(|text| !text.contains('\n'))
16551                            .unique()
16552                            .take(3)
16553                            .join(", ");
16554                        if target.is_empty() {
16555                            tab_kind.to_owned()
16556                        } else {
16557                            format!("{tab_kind} for {target}")
16558                        }
16559                    })
16560                    .context("buffer title")?;
16561
16562                let opened = workspace
16563                    .update_in(cx, |workspace, window, cx| {
16564                        Self::open_locations_in_multibuffer(
16565                            workspace,
16566                            locations,
16567                            title,
16568                            split,
16569                            MultibufferSelectionMode::First,
16570                            window,
16571                            cx,
16572                        )
16573                    })
16574                    .is_ok();
16575
16576                anyhow::Ok(Navigated::from_bool(opened))
16577            } else if num_locations == 0 {
16578                // If there is one url or file, open it directly
16579                match first_url_or_file {
16580                    Some(Either::Left(url)) => {
16581                        cx.update(|_, cx| cx.open_url(&url))?;
16582                        Ok(Navigated::Yes)
16583                    }
16584                    Some(Either::Right(path)) => {
16585                        let Some(workspace) = workspace else {
16586                            return Ok(Navigated::No);
16587                        };
16588
16589                        workspace
16590                            .update_in(cx, |workspace, window, cx| {
16591                                workspace.open_resolved_path(path, window, cx)
16592                            })?
16593                            .await?;
16594                        Ok(Navigated::Yes)
16595                    }
16596                    None => Ok(Navigated::No),
16597                }
16598            } else {
16599                let Some(workspace) = workspace else {
16600                    return Ok(Navigated::No);
16601                };
16602
16603                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16604                let target_range = target_ranges.first().unwrap().clone();
16605
16606                editor.update_in(cx, |editor, window, cx| {
16607                    let range = target_range.to_point(target_buffer.read(cx));
16608                    let range = editor.range_for_match(&range);
16609                    let range = collapse_multiline_range(range);
16610
16611                    if !split
16612                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16613                    {
16614                        editor.go_to_singleton_buffer_range(range, window, cx);
16615                    } else {
16616                        let pane = workspace.read(cx).active_pane().clone();
16617                        window.defer(cx, move |window, cx| {
16618                            let target_editor: Entity<Self> =
16619                                workspace.update(cx, |workspace, cx| {
16620                                    let pane = if split {
16621                                        workspace.adjacent_pane(window, cx)
16622                                    } else {
16623                                        workspace.active_pane().clone()
16624                                    };
16625
16626                                    workspace.open_project_item(
16627                                        pane,
16628                                        target_buffer.clone(),
16629                                        true,
16630                                        true,
16631                                        window,
16632                                        cx,
16633                                    )
16634                                });
16635                            target_editor.update(cx, |target_editor, cx| {
16636                                // When selecting a definition in a different buffer, disable the nav history
16637                                // to avoid creating a history entry at the previous cursor location.
16638                                pane.update(cx, |pane, _| pane.disable_history());
16639                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16640                                pane.update(cx, |pane, _| pane.enable_history());
16641                            });
16642                        });
16643                    }
16644                    Navigated::Yes
16645                })
16646            }
16647        })
16648    }
16649
16650    fn compute_target_location(
16651        &self,
16652        lsp_location: lsp::Location,
16653        server_id: LanguageServerId,
16654        window: &mut Window,
16655        cx: &mut Context<Self>,
16656    ) -> Task<anyhow::Result<Option<Location>>> {
16657        let Some(project) = self.project.clone() else {
16658            return Task::ready(Ok(None));
16659        };
16660
16661        cx.spawn_in(window, async move |editor, cx| {
16662            let location_task = editor.update(cx, |_, cx| {
16663                project.update(cx, |project, cx| {
16664                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16665                })
16666            })?;
16667            let location = Some({
16668                let target_buffer_handle = location_task.await.context("open local buffer")?;
16669                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16670                    let target_start = target_buffer
16671                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16672                    let target_end = target_buffer
16673                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16674                    target_buffer.anchor_after(target_start)
16675                        ..target_buffer.anchor_before(target_end)
16676                })?;
16677                Location {
16678                    buffer: target_buffer_handle,
16679                    range,
16680                }
16681            });
16682            Ok(location)
16683        })
16684    }
16685
16686    fn go_to_next_reference(
16687        &mut self,
16688        _: &GoToNextReference,
16689        window: &mut Window,
16690        cx: &mut Context<Self>,
16691    ) {
16692        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16693        if let Some(task) = task {
16694            task.detach();
16695        };
16696    }
16697
16698    fn go_to_prev_reference(
16699        &mut self,
16700        _: &GoToPreviousReference,
16701        window: &mut Window,
16702        cx: &mut Context<Self>,
16703    ) {
16704        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16705        if let Some(task) = task {
16706            task.detach();
16707        };
16708    }
16709
16710    pub fn go_to_reference_before_or_after_position(
16711        &mut self,
16712        direction: Direction,
16713        count: usize,
16714        window: &mut Window,
16715        cx: &mut Context<Self>,
16716    ) -> Option<Task<Result<()>>> {
16717        let selection = self.selections.newest_anchor();
16718        let head = selection.head();
16719
16720        let multi_buffer = self.buffer.read(cx);
16721
16722        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16723        let workspace = self.workspace()?;
16724        let project = workspace.read(cx).project().clone();
16725        let references =
16726            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16727        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16728            let Some(locations) = references.await? else {
16729                return Ok(());
16730            };
16731
16732            if locations.is_empty() {
16733                // totally normal - the cursor may be on something which is not
16734                // a symbol (e.g. a keyword)
16735                log::info!("no references found under cursor");
16736                return Ok(());
16737            }
16738
16739            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16740
16741            let multi_buffer_snapshot =
16742                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16743
16744            let (locations, current_location_index) =
16745                multi_buffer.update(cx, |multi_buffer, cx| {
16746                    let mut locations = locations
16747                        .into_iter()
16748                        .filter_map(|loc| {
16749                            let start = multi_buffer.buffer_anchor_to_anchor(
16750                                &loc.buffer,
16751                                loc.range.start,
16752                                cx,
16753                            )?;
16754                            let end = multi_buffer.buffer_anchor_to_anchor(
16755                                &loc.buffer,
16756                                loc.range.end,
16757                                cx,
16758                            )?;
16759                            Some(start..end)
16760                        })
16761                        .collect::<Vec<_>>();
16762
16763                    // There is an O(n) implementation, but given this list will be
16764                    // small (usually <100 items), the extra O(log(n)) factor isn't
16765                    // worth the (surprisingly large amount of) extra complexity.
16766                    locations
16767                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16768
16769                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16770
16771                    let current_location_index = locations.iter().position(|loc| {
16772                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16773                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16774                    });
16775
16776                    (locations, current_location_index)
16777                })?;
16778
16779            let Some(current_location_index) = current_location_index else {
16780                // This indicates something has gone wrong, because we already
16781                // handle the "no references" case above
16782                log::error!(
16783                    "failed to find current reference under cursor. Total references: {}",
16784                    locations.len()
16785                );
16786                return Ok(());
16787            };
16788
16789            let destination_location_index = match direction {
16790                Direction::Next => (current_location_index + count) % locations.len(),
16791                Direction::Prev => {
16792                    (current_location_index + locations.len() - count % locations.len())
16793                        % locations.len()
16794                }
16795            };
16796
16797            // TODO(cameron): is this needed?
16798            // the thinking is to avoid "jumping to the current location" (avoid
16799            // polluting "jumplist" in vim terms)
16800            if current_location_index == destination_location_index {
16801                return Ok(());
16802            }
16803
16804            let Range { start, end } = locations[destination_location_index];
16805
16806            editor.update_in(cx, |editor, window, cx| {
16807                let effects = SelectionEffects::default();
16808
16809                editor.unfold_ranges(&[start..end], false, false, cx);
16810                editor.change_selections(effects, window, cx, |s| {
16811                    s.select_ranges([start..start]);
16812                });
16813            })?;
16814
16815            Ok(())
16816        }))
16817    }
16818
16819    pub fn find_all_references(
16820        &mut self,
16821        _: &FindAllReferences,
16822        window: &mut Window,
16823        cx: &mut Context<Self>,
16824    ) -> Option<Task<Result<Navigated>>> {
16825        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16826        let multi_buffer = self.buffer.read(cx);
16827        let head = selection.head();
16828
16829        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16830        let head_anchor = multi_buffer_snapshot.anchor_at(
16831            head,
16832            if head < selection.tail() {
16833                Bias::Right
16834            } else {
16835                Bias::Left
16836            },
16837        );
16838
16839        match self
16840            .find_all_references_task_sources
16841            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16842        {
16843            Ok(_) => {
16844                log::info!(
16845                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16846                );
16847                return None;
16848            }
16849            Err(i) => {
16850                self.find_all_references_task_sources.insert(i, head_anchor);
16851            }
16852        }
16853
16854        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16855        let workspace = self.workspace()?;
16856        let project = workspace.read(cx).project().clone();
16857        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16858        Some(cx.spawn_in(window, async move |editor, cx| {
16859            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16860                if let Ok(i) = editor
16861                    .find_all_references_task_sources
16862                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16863                {
16864                    editor.find_all_references_task_sources.remove(i);
16865                }
16866            });
16867
16868            let Some(locations) = references.await? else {
16869                return anyhow::Ok(Navigated::No);
16870            };
16871            let mut locations = cx.update(|_, cx| {
16872                locations
16873                    .into_iter()
16874                    .map(|location| {
16875                        let buffer = location.buffer.read(cx);
16876                        (location.buffer, location.range.to_point(buffer))
16877                    })
16878                    .into_group_map()
16879            })?;
16880            if locations.is_empty() {
16881                return anyhow::Ok(Navigated::No);
16882            }
16883            for ranges in locations.values_mut() {
16884                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16885                ranges.dedup();
16886            }
16887
16888            workspace.update_in(cx, |workspace, window, cx| {
16889                let target = locations
16890                    .iter()
16891                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16892                    .map(|(buffer, location)| {
16893                        buffer
16894                            .read(cx)
16895                            .text_for_range(location.clone())
16896                            .collect::<String>()
16897                    })
16898                    .filter(|text| !text.contains('\n'))
16899                    .unique()
16900                    .take(3)
16901                    .join(", ");
16902                let title = if target.is_empty() {
16903                    "References".to_owned()
16904                } else {
16905                    format!("References to {target}")
16906                };
16907                Self::open_locations_in_multibuffer(
16908                    workspace,
16909                    locations,
16910                    title,
16911                    false,
16912                    MultibufferSelectionMode::First,
16913                    window,
16914                    cx,
16915                );
16916                Navigated::Yes
16917            })
16918        }))
16919    }
16920
16921    /// Opens a multibuffer with the given project locations in it
16922    pub fn open_locations_in_multibuffer(
16923        workspace: &mut Workspace,
16924        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16925        title: String,
16926        split: bool,
16927        multibuffer_selection_mode: MultibufferSelectionMode,
16928        window: &mut Window,
16929        cx: &mut Context<Workspace>,
16930    ) {
16931        if locations.is_empty() {
16932            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16933            return;
16934        }
16935
16936        let capability = workspace.project().read(cx).capability();
16937        let mut ranges = <Vec<Range<Anchor>>>::new();
16938
16939        // a key to find existing multibuffer editors with the same set of locations
16940        // to prevent us from opening more and more multibuffer tabs for searches and the like
16941        let mut key = (title.clone(), vec![]);
16942        let excerpt_buffer = cx.new(|cx| {
16943            let key = &mut key.1;
16944            let mut multibuffer = MultiBuffer::new(capability);
16945            for (buffer, mut ranges_for_buffer) in locations {
16946                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16947                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16948                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16949                    PathKey::for_buffer(&buffer, cx),
16950                    buffer.clone(),
16951                    ranges_for_buffer,
16952                    multibuffer_context_lines(cx),
16953                    cx,
16954                );
16955                ranges.extend(new_ranges)
16956            }
16957
16958            multibuffer.with_title(title)
16959        });
16960        let existing = workspace.active_pane().update(cx, |pane, cx| {
16961            pane.items()
16962                .filter_map(|item| item.downcast::<Editor>())
16963                .find(|editor| {
16964                    editor
16965                        .read(cx)
16966                        .lookup_key
16967                        .as_ref()
16968                        .and_then(|it| {
16969                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16970                        })
16971                        .is_some_and(|it| *it == key)
16972                })
16973        });
16974        let editor = existing.unwrap_or_else(|| {
16975            cx.new(|cx| {
16976                let mut editor = Editor::for_multibuffer(
16977                    excerpt_buffer,
16978                    Some(workspace.project().clone()),
16979                    window,
16980                    cx,
16981                );
16982                editor.lookup_key = Some(Box::new(key));
16983                editor
16984            })
16985        });
16986        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
16987            MultibufferSelectionMode::First => {
16988                if let Some(first_range) = ranges.first() {
16989                    editor.change_selections(
16990                        SelectionEffects::no_scroll(),
16991                        window,
16992                        cx,
16993                        |selections| {
16994                            selections.clear_disjoint();
16995                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
16996                        },
16997                    );
16998                }
16999                editor.highlight_background::<Self>(
17000                    &ranges,
17001                    |theme| theme.colors().editor_highlighted_line_background,
17002                    cx,
17003                );
17004            }
17005            MultibufferSelectionMode::All => {
17006                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17007                    selections.clear_disjoint();
17008                    selections.select_anchor_ranges(ranges);
17009                });
17010            }
17011        });
17012
17013        let item = Box::new(editor);
17014        let item_id = item.item_id();
17015
17016        if split {
17017            let pane = workspace.adjacent_pane(window, cx);
17018            workspace.add_item(pane, item, None, true, true, window, cx);
17019        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17020            let (preview_item_id, preview_item_idx) =
17021                workspace.active_pane().read_with(cx, |pane, _| {
17022                    (pane.preview_item_id(), pane.preview_item_idx())
17023                });
17024
17025            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17026
17027            if let Some(preview_item_id) = preview_item_id {
17028                workspace.active_pane().update(cx, |pane, cx| {
17029                    pane.remove_item(preview_item_id, false, false, window, cx);
17030                });
17031            }
17032        } else {
17033            workspace.add_item_to_active_pane(item, None, true, window, cx);
17034        }
17035        workspace.active_pane().update(cx, |pane, cx| {
17036            pane.set_preview_item_id(Some(item_id), cx);
17037        });
17038    }
17039
17040    pub fn rename(
17041        &mut self,
17042        _: &Rename,
17043        window: &mut Window,
17044        cx: &mut Context<Self>,
17045    ) -> Option<Task<Result<()>>> {
17046        use language::ToOffset as _;
17047
17048        let provider = self.semantics_provider.clone()?;
17049        let selection = self.selections.newest_anchor().clone();
17050        let (cursor_buffer, cursor_buffer_position) = self
17051            .buffer
17052            .read(cx)
17053            .text_anchor_for_position(selection.head(), cx)?;
17054        let (tail_buffer, cursor_buffer_position_end) = self
17055            .buffer
17056            .read(cx)
17057            .text_anchor_for_position(selection.tail(), cx)?;
17058        if tail_buffer != cursor_buffer {
17059            return None;
17060        }
17061
17062        let snapshot = cursor_buffer.read(cx).snapshot();
17063        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17064        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17065        let prepare_rename = provider
17066            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17067            .unwrap_or_else(|| Task::ready(Ok(None)));
17068        drop(snapshot);
17069
17070        Some(cx.spawn_in(window, async move |this, cx| {
17071            let rename_range = if let Some(range) = prepare_rename.await? {
17072                Some(range)
17073            } else {
17074                this.update(cx, |this, cx| {
17075                    let buffer = this.buffer.read(cx).snapshot(cx);
17076                    let mut buffer_highlights = this
17077                        .document_highlights_for_position(selection.head(), &buffer)
17078                        .filter(|highlight| {
17079                            highlight.start.excerpt_id == selection.head().excerpt_id
17080                                && highlight.end.excerpt_id == selection.head().excerpt_id
17081                        });
17082                    buffer_highlights
17083                        .next()
17084                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17085                })?
17086            };
17087            if let Some(rename_range) = rename_range {
17088                this.update_in(cx, |this, window, cx| {
17089                    let snapshot = cursor_buffer.read(cx).snapshot();
17090                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17091                    let cursor_offset_in_rename_range =
17092                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17093                    let cursor_offset_in_rename_range_end =
17094                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17095
17096                    this.take_rename(false, window, cx);
17097                    let buffer = this.buffer.read(cx).read(cx);
17098                    let cursor_offset = selection.head().to_offset(&buffer);
17099                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17100                    let rename_end = rename_start + rename_buffer_range.len();
17101                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17102                    let mut old_highlight_id = None;
17103                    let old_name: Arc<str> = buffer
17104                        .chunks(rename_start..rename_end, true)
17105                        .map(|chunk| {
17106                            if old_highlight_id.is_none() {
17107                                old_highlight_id = chunk.syntax_highlight_id;
17108                            }
17109                            chunk.text
17110                        })
17111                        .collect::<String>()
17112                        .into();
17113
17114                    drop(buffer);
17115
17116                    // Position the selection in the rename editor so that it matches the current selection.
17117                    this.show_local_selections = false;
17118                    let rename_editor = cx.new(|cx| {
17119                        let mut editor = Editor::single_line(window, cx);
17120                        editor.buffer.update(cx, |buffer, cx| {
17121                            buffer.edit([(0..0, old_name.clone())], None, cx)
17122                        });
17123                        let rename_selection_range = match cursor_offset_in_rename_range
17124                            .cmp(&cursor_offset_in_rename_range_end)
17125                        {
17126                            Ordering::Equal => {
17127                                editor.select_all(&SelectAll, window, cx);
17128                                return editor;
17129                            }
17130                            Ordering::Less => {
17131                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17132                            }
17133                            Ordering::Greater => {
17134                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17135                            }
17136                        };
17137                        if rename_selection_range.end > old_name.len() {
17138                            editor.select_all(&SelectAll, window, cx);
17139                        } else {
17140                            editor.change_selections(Default::default(), window, cx, |s| {
17141                                s.select_ranges([rename_selection_range]);
17142                            });
17143                        }
17144                        editor
17145                    });
17146                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17147                        if e == &EditorEvent::Focused {
17148                            cx.emit(EditorEvent::FocusedIn)
17149                        }
17150                    })
17151                    .detach();
17152
17153                    let write_highlights =
17154                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17155                    let read_highlights =
17156                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17157                    let ranges = write_highlights
17158                        .iter()
17159                        .flat_map(|(_, ranges)| ranges.iter())
17160                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17161                        .cloned()
17162                        .collect();
17163
17164                    this.highlight_text::<Rename>(
17165                        ranges,
17166                        HighlightStyle {
17167                            fade_out: Some(0.6),
17168                            ..Default::default()
17169                        },
17170                        cx,
17171                    );
17172                    let rename_focus_handle = rename_editor.focus_handle(cx);
17173                    window.focus(&rename_focus_handle);
17174                    let block_id = this.insert_blocks(
17175                        [BlockProperties {
17176                            style: BlockStyle::Flex,
17177                            placement: BlockPlacement::Below(range.start),
17178                            height: Some(1),
17179                            render: Arc::new({
17180                                let rename_editor = rename_editor.clone();
17181                                move |cx: &mut BlockContext| {
17182                                    let mut text_style = cx.editor_style.text.clone();
17183                                    if let Some(highlight_style) = old_highlight_id
17184                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17185                                    {
17186                                        text_style = text_style.highlight(highlight_style);
17187                                    }
17188                                    div()
17189                                        .block_mouse_except_scroll()
17190                                        .pl(cx.anchor_x)
17191                                        .child(EditorElement::new(
17192                                            &rename_editor,
17193                                            EditorStyle {
17194                                                background: cx.theme().system().transparent,
17195                                                local_player: cx.editor_style.local_player,
17196                                                text: text_style,
17197                                                scrollbar_width: cx.editor_style.scrollbar_width,
17198                                                syntax: cx.editor_style.syntax.clone(),
17199                                                status: cx.editor_style.status.clone(),
17200                                                inlay_hints_style: HighlightStyle {
17201                                                    font_weight: Some(FontWeight::BOLD),
17202                                                    ..make_inlay_hints_style(cx.app)
17203                                                },
17204                                                edit_prediction_styles: make_suggestion_styles(
17205                                                    cx.app,
17206                                                ),
17207                                                ..EditorStyle::default()
17208                                            },
17209                                        ))
17210                                        .into_any_element()
17211                                }
17212                            }),
17213                            priority: 0,
17214                        }],
17215                        Some(Autoscroll::fit()),
17216                        cx,
17217                    )[0];
17218                    this.pending_rename = Some(RenameState {
17219                        range,
17220                        old_name,
17221                        editor: rename_editor,
17222                        block_id,
17223                    });
17224                })?;
17225            }
17226
17227            Ok(())
17228        }))
17229    }
17230
17231    pub fn confirm_rename(
17232        &mut self,
17233        _: &ConfirmRename,
17234        window: &mut Window,
17235        cx: &mut Context<Self>,
17236    ) -> Option<Task<Result<()>>> {
17237        let rename = self.take_rename(false, window, cx)?;
17238        let workspace = self.workspace()?.downgrade();
17239        let (buffer, start) = self
17240            .buffer
17241            .read(cx)
17242            .text_anchor_for_position(rename.range.start, cx)?;
17243        let (end_buffer, _) = self
17244            .buffer
17245            .read(cx)
17246            .text_anchor_for_position(rename.range.end, cx)?;
17247        if buffer != end_buffer {
17248            return None;
17249        }
17250
17251        let old_name = rename.old_name;
17252        let new_name = rename.editor.read(cx).text(cx);
17253
17254        let rename = self.semantics_provider.as_ref()?.perform_rename(
17255            &buffer,
17256            start,
17257            new_name.clone(),
17258            cx,
17259        )?;
17260
17261        Some(cx.spawn_in(window, async move |editor, cx| {
17262            let project_transaction = rename.await?;
17263            Self::open_project_transaction(
17264                &editor,
17265                workspace,
17266                project_transaction,
17267                format!("Rename: {}{}", old_name, new_name),
17268                cx,
17269            )
17270            .await?;
17271
17272            editor.update(cx, |editor, cx| {
17273                editor.refresh_document_highlights(cx);
17274            })?;
17275            Ok(())
17276        }))
17277    }
17278
17279    fn take_rename(
17280        &mut self,
17281        moving_cursor: bool,
17282        window: &mut Window,
17283        cx: &mut Context<Self>,
17284    ) -> Option<RenameState> {
17285        let rename = self.pending_rename.take()?;
17286        if rename.editor.focus_handle(cx).is_focused(window) {
17287            window.focus(&self.focus_handle);
17288        }
17289
17290        self.remove_blocks(
17291            [rename.block_id].into_iter().collect(),
17292            Some(Autoscroll::fit()),
17293            cx,
17294        );
17295        self.clear_highlights::<Rename>(cx);
17296        self.show_local_selections = true;
17297
17298        if moving_cursor {
17299            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17300                editor
17301                    .selections
17302                    .newest::<usize>(&editor.display_snapshot(cx))
17303                    .head()
17304            });
17305
17306            // Update the selection to match the position of the selection inside
17307            // the rename editor.
17308            let snapshot = self.buffer.read(cx).read(cx);
17309            let rename_range = rename.range.to_offset(&snapshot);
17310            let cursor_in_editor = snapshot
17311                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17312                .min(rename_range.end);
17313            drop(snapshot);
17314
17315            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17316                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17317            });
17318        } else {
17319            self.refresh_document_highlights(cx);
17320        }
17321
17322        Some(rename)
17323    }
17324
17325    pub fn pending_rename(&self) -> Option<&RenameState> {
17326        self.pending_rename.as_ref()
17327    }
17328
17329    fn format(
17330        &mut self,
17331        _: &Format,
17332        window: &mut Window,
17333        cx: &mut Context<Self>,
17334    ) -> Option<Task<Result<()>>> {
17335        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17336
17337        let project = match &self.project {
17338            Some(project) => project.clone(),
17339            None => return None,
17340        };
17341
17342        Some(self.perform_format(
17343            project,
17344            FormatTrigger::Manual,
17345            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17346            window,
17347            cx,
17348        ))
17349    }
17350
17351    fn format_selections(
17352        &mut self,
17353        _: &FormatSelections,
17354        window: &mut Window,
17355        cx: &mut Context<Self>,
17356    ) -> Option<Task<Result<()>>> {
17357        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17358
17359        let project = match &self.project {
17360            Some(project) => project.clone(),
17361            None => return None,
17362        };
17363
17364        let ranges = self
17365            .selections
17366            .all_adjusted(&self.display_snapshot(cx))
17367            .into_iter()
17368            .map(|selection| selection.range())
17369            .collect_vec();
17370
17371        Some(self.perform_format(
17372            project,
17373            FormatTrigger::Manual,
17374            FormatTarget::Ranges(ranges),
17375            window,
17376            cx,
17377        ))
17378    }
17379
17380    fn perform_format(
17381        &mut self,
17382        project: Entity<Project>,
17383        trigger: FormatTrigger,
17384        target: FormatTarget,
17385        window: &mut Window,
17386        cx: &mut Context<Self>,
17387    ) -> Task<Result<()>> {
17388        let buffer = self.buffer.clone();
17389        let (buffers, target) = match target {
17390            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17391            FormatTarget::Ranges(selection_ranges) => {
17392                let multi_buffer = buffer.read(cx);
17393                let snapshot = multi_buffer.read(cx);
17394                let mut buffers = HashSet::default();
17395                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17396                    BTreeMap::new();
17397                for selection_range in selection_ranges {
17398                    for (buffer, buffer_range, _) in
17399                        snapshot.range_to_buffer_ranges(selection_range)
17400                    {
17401                        let buffer_id = buffer.remote_id();
17402                        let start = buffer.anchor_before(buffer_range.start);
17403                        let end = buffer.anchor_after(buffer_range.end);
17404                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17405                        buffer_id_to_ranges
17406                            .entry(buffer_id)
17407                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17408                            .or_insert_with(|| vec![start..end]);
17409                    }
17410                }
17411                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17412            }
17413        };
17414
17415        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17416        let selections_prev = transaction_id_prev
17417            .and_then(|transaction_id_prev| {
17418                // default to selections as they were after the last edit, if we have them,
17419                // instead of how they are now.
17420                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17421                // will take you back to where you made the last edit, instead of staying where you scrolled
17422                self.selection_history
17423                    .transaction(transaction_id_prev)
17424                    .map(|t| t.0.clone())
17425            })
17426            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17427
17428        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17429        let format = project.update(cx, |project, cx| {
17430            project.format(buffers, target, true, trigger, cx)
17431        });
17432
17433        cx.spawn_in(window, async move |editor, cx| {
17434            let transaction = futures::select_biased! {
17435                transaction = format.log_err().fuse() => transaction,
17436                () = timeout => {
17437                    log::warn!("timed out waiting for formatting");
17438                    None
17439                }
17440            };
17441
17442            buffer
17443                .update(cx, |buffer, cx| {
17444                    if let Some(transaction) = transaction
17445                        && !buffer.is_singleton()
17446                    {
17447                        buffer.push_transaction(&transaction.0, cx);
17448                    }
17449                    cx.notify();
17450                })
17451                .ok();
17452
17453            if let Some(transaction_id_now) =
17454                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17455            {
17456                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17457                if has_new_transaction {
17458                    _ = editor.update(cx, |editor, _| {
17459                        editor
17460                            .selection_history
17461                            .insert_transaction(transaction_id_now, selections_prev);
17462                    });
17463                }
17464            }
17465
17466            Ok(())
17467        })
17468    }
17469
17470    fn organize_imports(
17471        &mut self,
17472        _: &OrganizeImports,
17473        window: &mut Window,
17474        cx: &mut Context<Self>,
17475    ) -> Option<Task<Result<()>>> {
17476        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17477        let project = match &self.project {
17478            Some(project) => project.clone(),
17479            None => return None,
17480        };
17481        Some(self.perform_code_action_kind(
17482            project,
17483            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17484            window,
17485            cx,
17486        ))
17487    }
17488
17489    fn perform_code_action_kind(
17490        &mut self,
17491        project: Entity<Project>,
17492        kind: CodeActionKind,
17493        window: &mut Window,
17494        cx: &mut Context<Self>,
17495    ) -> Task<Result<()>> {
17496        let buffer = self.buffer.clone();
17497        let buffers = buffer.read(cx).all_buffers();
17498        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17499        let apply_action = project.update(cx, |project, cx| {
17500            project.apply_code_action_kind(buffers, kind, true, cx)
17501        });
17502        cx.spawn_in(window, async move |_, cx| {
17503            let transaction = futures::select_biased! {
17504                () = timeout => {
17505                    log::warn!("timed out waiting for executing code action");
17506                    None
17507                }
17508                transaction = apply_action.log_err().fuse() => transaction,
17509            };
17510            buffer
17511                .update(cx, |buffer, cx| {
17512                    // check if we need this
17513                    if let Some(transaction) = transaction
17514                        && !buffer.is_singleton()
17515                    {
17516                        buffer.push_transaction(&transaction.0, cx);
17517                    }
17518                    cx.notify();
17519                })
17520                .ok();
17521            Ok(())
17522        })
17523    }
17524
17525    pub fn restart_language_server(
17526        &mut self,
17527        _: &RestartLanguageServer,
17528        _: &mut Window,
17529        cx: &mut Context<Self>,
17530    ) {
17531        if let Some(project) = self.project.clone() {
17532            self.buffer.update(cx, |multi_buffer, cx| {
17533                project.update(cx, |project, cx| {
17534                    project.restart_language_servers_for_buffers(
17535                        multi_buffer.all_buffers().into_iter().collect(),
17536                        HashSet::default(),
17537                        cx,
17538                    );
17539                });
17540            })
17541        }
17542    }
17543
17544    pub fn stop_language_server(
17545        &mut self,
17546        _: &StopLanguageServer,
17547        _: &mut Window,
17548        cx: &mut Context<Self>,
17549    ) {
17550        if let Some(project) = self.project.clone() {
17551            self.buffer.update(cx, |multi_buffer, cx| {
17552                project.update(cx, |project, cx| {
17553                    project.stop_language_servers_for_buffers(
17554                        multi_buffer.all_buffers().into_iter().collect(),
17555                        HashSet::default(),
17556                        cx,
17557                    );
17558                });
17559            });
17560            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17561        }
17562    }
17563
17564    fn cancel_language_server_work(
17565        workspace: &mut Workspace,
17566        _: &actions::CancelLanguageServerWork,
17567        _: &mut Window,
17568        cx: &mut Context<Workspace>,
17569    ) {
17570        let project = workspace.project();
17571        let buffers = workspace
17572            .active_item(cx)
17573            .and_then(|item| item.act_as::<Editor>(cx))
17574            .map_or(HashSet::default(), |editor| {
17575                editor.read(cx).buffer.read(cx).all_buffers()
17576            });
17577        project.update(cx, |project, cx| {
17578            project.cancel_language_server_work_for_buffers(buffers, cx);
17579        });
17580    }
17581
17582    fn show_character_palette(
17583        &mut self,
17584        _: &ShowCharacterPalette,
17585        window: &mut Window,
17586        _: &mut Context<Self>,
17587    ) {
17588        window.show_character_palette();
17589    }
17590
17591    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17592        if !self.diagnostics_enabled() {
17593            return;
17594        }
17595
17596        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17597            let buffer = self.buffer.read(cx).snapshot(cx);
17598            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17599            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17600            let is_valid = buffer
17601                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17602                .any(|entry| {
17603                    entry.diagnostic.is_primary
17604                        && !entry.range.is_empty()
17605                        && entry.range.start == primary_range_start
17606                        && entry.diagnostic.message == active_diagnostics.active_message
17607                });
17608
17609            if !is_valid {
17610                self.dismiss_diagnostics(cx);
17611            }
17612        }
17613    }
17614
17615    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17616        match &self.active_diagnostics {
17617            ActiveDiagnostic::Group(group) => Some(group),
17618            _ => None,
17619        }
17620    }
17621
17622    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17623        if !self.diagnostics_enabled() {
17624            return;
17625        }
17626        self.dismiss_diagnostics(cx);
17627        self.active_diagnostics = ActiveDiagnostic::All;
17628    }
17629
17630    fn activate_diagnostics(
17631        &mut self,
17632        buffer_id: BufferId,
17633        diagnostic: DiagnosticEntryRef<'_, usize>,
17634        window: &mut Window,
17635        cx: &mut Context<Self>,
17636    ) {
17637        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17638            return;
17639        }
17640        self.dismiss_diagnostics(cx);
17641        let snapshot = self.snapshot(window, cx);
17642        let buffer = self.buffer.read(cx).snapshot(cx);
17643        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17644            return;
17645        };
17646
17647        let diagnostic_group = buffer
17648            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17649            .collect::<Vec<_>>();
17650
17651        let blocks =
17652            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17653
17654        let blocks = self.display_map.update(cx, |display_map, cx| {
17655            display_map.insert_blocks(blocks, cx).into_iter().collect()
17656        });
17657        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17658            active_range: buffer.anchor_before(diagnostic.range.start)
17659                ..buffer.anchor_after(diagnostic.range.end),
17660            active_message: diagnostic.diagnostic.message.clone(),
17661            group_id: diagnostic.diagnostic.group_id,
17662            blocks,
17663        });
17664        cx.notify();
17665    }
17666
17667    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17668        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17669            return;
17670        };
17671
17672        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17673        if let ActiveDiagnostic::Group(group) = prev {
17674            self.display_map.update(cx, |display_map, cx| {
17675                display_map.remove_blocks(group.blocks, cx);
17676            });
17677            cx.notify();
17678        }
17679    }
17680
17681    /// Disable inline diagnostics rendering for this editor.
17682    pub fn disable_inline_diagnostics(&mut self) {
17683        self.inline_diagnostics_enabled = false;
17684        self.inline_diagnostics_update = Task::ready(());
17685        self.inline_diagnostics.clear();
17686    }
17687
17688    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17689        self.diagnostics_enabled = false;
17690        self.dismiss_diagnostics(cx);
17691        self.inline_diagnostics_update = Task::ready(());
17692        self.inline_diagnostics.clear();
17693    }
17694
17695    pub fn disable_word_completions(&mut self) {
17696        self.word_completions_enabled = false;
17697    }
17698
17699    pub fn diagnostics_enabled(&self) -> bool {
17700        self.diagnostics_enabled && self.mode.is_full()
17701    }
17702
17703    pub fn inline_diagnostics_enabled(&self) -> bool {
17704        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17705    }
17706
17707    pub fn show_inline_diagnostics(&self) -> bool {
17708        self.show_inline_diagnostics
17709    }
17710
17711    pub fn toggle_inline_diagnostics(
17712        &mut self,
17713        _: &ToggleInlineDiagnostics,
17714        window: &mut Window,
17715        cx: &mut Context<Editor>,
17716    ) {
17717        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17718        self.refresh_inline_diagnostics(false, window, cx);
17719    }
17720
17721    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17722        self.diagnostics_max_severity = severity;
17723        self.display_map.update(cx, |display_map, _| {
17724            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17725        });
17726    }
17727
17728    pub fn toggle_diagnostics(
17729        &mut self,
17730        _: &ToggleDiagnostics,
17731        window: &mut Window,
17732        cx: &mut Context<Editor>,
17733    ) {
17734        if !self.diagnostics_enabled() {
17735            return;
17736        }
17737
17738        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17739            EditorSettings::get_global(cx)
17740                .diagnostics_max_severity
17741                .filter(|severity| severity != &DiagnosticSeverity::Off)
17742                .unwrap_or(DiagnosticSeverity::Hint)
17743        } else {
17744            DiagnosticSeverity::Off
17745        };
17746        self.set_max_diagnostics_severity(new_severity, cx);
17747        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17748            self.active_diagnostics = ActiveDiagnostic::None;
17749            self.inline_diagnostics_update = Task::ready(());
17750            self.inline_diagnostics.clear();
17751        } else {
17752            self.refresh_inline_diagnostics(false, window, cx);
17753        }
17754
17755        cx.notify();
17756    }
17757
17758    pub fn toggle_minimap(
17759        &mut self,
17760        _: &ToggleMinimap,
17761        window: &mut Window,
17762        cx: &mut Context<Editor>,
17763    ) {
17764        if self.supports_minimap(cx) {
17765            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17766        }
17767    }
17768
17769    fn refresh_inline_diagnostics(
17770        &mut self,
17771        debounce: bool,
17772        window: &mut Window,
17773        cx: &mut Context<Self>,
17774    ) {
17775        let max_severity = ProjectSettings::get_global(cx)
17776            .diagnostics
17777            .inline
17778            .max_severity
17779            .unwrap_or(self.diagnostics_max_severity);
17780
17781        if !self.inline_diagnostics_enabled()
17782            || !self.show_inline_diagnostics
17783            || max_severity == DiagnosticSeverity::Off
17784        {
17785            self.inline_diagnostics_update = Task::ready(());
17786            self.inline_diagnostics.clear();
17787            return;
17788        }
17789
17790        let debounce_ms = ProjectSettings::get_global(cx)
17791            .diagnostics
17792            .inline
17793            .update_debounce_ms;
17794        let debounce = if debounce && debounce_ms > 0 {
17795            Some(Duration::from_millis(debounce_ms))
17796        } else {
17797            None
17798        };
17799        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17800            if let Some(debounce) = debounce {
17801                cx.background_executor().timer(debounce).await;
17802            }
17803            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17804                editor
17805                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17806                    .ok()
17807            }) else {
17808                return;
17809            };
17810
17811            let new_inline_diagnostics = cx
17812                .background_spawn(async move {
17813                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17814                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17815                        let message = diagnostic_entry
17816                            .diagnostic
17817                            .message
17818                            .split_once('\n')
17819                            .map(|(line, _)| line)
17820                            .map(SharedString::new)
17821                            .unwrap_or_else(|| {
17822                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17823                            });
17824                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17825                        let (Ok(i) | Err(i)) = inline_diagnostics
17826                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17827                        inline_diagnostics.insert(
17828                            i,
17829                            (
17830                                start_anchor,
17831                                InlineDiagnostic {
17832                                    message,
17833                                    group_id: diagnostic_entry.diagnostic.group_id,
17834                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17835                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17836                                    severity: diagnostic_entry.diagnostic.severity,
17837                                },
17838                            ),
17839                        );
17840                    }
17841                    inline_diagnostics
17842                })
17843                .await;
17844
17845            editor
17846                .update(cx, |editor, cx| {
17847                    editor.inline_diagnostics = new_inline_diagnostics;
17848                    cx.notify();
17849                })
17850                .ok();
17851        });
17852    }
17853
17854    fn pull_diagnostics(
17855        &mut self,
17856        buffer_id: Option<BufferId>,
17857        window: &Window,
17858        cx: &mut Context<Self>,
17859    ) -> Option<()> {
17860        if self.ignore_lsp_data() {
17861            return None;
17862        }
17863        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17864            .diagnostics
17865            .lsp_pull_diagnostics;
17866        if !pull_diagnostics_settings.enabled {
17867            return None;
17868        }
17869        let project = self.project()?.downgrade();
17870        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17871        let mut buffers = self.buffer.read(cx).all_buffers();
17872        buffers.retain(|buffer| {
17873            let buffer_id_to_retain = buffer.read(cx).remote_id();
17874            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17875                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17876        });
17877        if buffers.is_empty() {
17878            self.pull_diagnostics_task = Task::ready(());
17879            return None;
17880        }
17881
17882        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17883            cx.background_executor().timer(debounce).await;
17884
17885            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17886                buffers
17887                    .into_iter()
17888                    .filter_map(|buffer| {
17889                        project
17890                            .update(cx, |project, cx| {
17891                                project.lsp_store().update(cx, |lsp_store, cx| {
17892                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17893                                })
17894                            })
17895                            .ok()
17896                    })
17897                    .collect::<FuturesUnordered<_>>()
17898            }) else {
17899                return;
17900            };
17901
17902            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17903                match pull_task {
17904                    Ok(()) => {
17905                        if editor
17906                            .update_in(cx, |editor, window, cx| {
17907                                editor.update_diagnostics_state(window, cx);
17908                            })
17909                            .is_err()
17910                        {
17911                            return;
17912                        }
17913                    }
17914                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17915                }
17916            }
17917        });
17918
17919        Some(())
17920    }
17921
17922    pub fn set_selections_from_remote(
17923        &mut self,
17924        selections: Vec<Selection<Anchor>>,
17925        pending_selection: Option<Selection<Anchor>>,
17926        window: &mut Window,
17927        cx: &mut Context<Self>,
17928    ) {
17929        let old_cursor_position = self.selections.newest_anchor().head();
17930        self.selections.change_with(cx, |s| {
17931            s.select_anchors(selections);
17932            if let Some(pending_selection) = pending_selection {
17933                s.set_pending(pending_selection, SelectMode::Character);
17934            } else {
17935                s.clear_pending();
17936            }
17937        });
17938        self.selections_did_change(
17939            false,
17940            &old_cursor_position,
17941            SelectionEffects::default(),
17942            window,
17943            cx,
17944        );
17945    }
17946
17947    pub fn transact(
17948        &mut self,
17949        window: &mut Window,
17950        cx: &mut Context<Self>,
17951        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17952    ) -> Option<TransactionId> {
17953        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17954            this.start_transaction_at(Instant::now(), window, cx);
17955            update(this, window, cx);
17956            this.end_transaction_at(Instant::now(), cx)
17957        })
17958    }
17959
17960    pub fn start_transaction_at(
17961        &mut self,
17962        now: Instant,
17963        window: &mut Window,
17964        cx: &mut Context<Self>,
17965    ) -> Option<TransactionId> {
17966        self.end_selection(window, cx);
17967        if let Some(tx_id) = self
17968            .buffer
17969            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17970        {
17971            self.selection_history
17972                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17973            cx.emit(EditorEvent::TransactionBegun {
17974                transaction_id: tx_id,
17975            });
17976            Some(tx_id)
17977        } else {
17978            None
17979        }
17980    }
17981
17982    pub fn end_transaction_at(
17983        &mut self,
17984        now: Instant,
17985        cx: &mut Context<Self>,
17986    ) -> Option<TransactionId> {
17987        if let Some(transaction_id) = self
17988            .buffer
17989            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17990        {
17991            if let Some((_, end_selections)) =
17992                self.selection_history.transaction_mut(transaction_id)
17993            {
17994                *end_selections = Some(self.selections.disjoint_anchors_arc());
17995            } else {
17996                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17997            }
17998
17999            cx.emit(EditorEvent::Edited { transaction_id });
18000            Some(transaction_id)
18001        } else {
18002            None
18003        }
18004    }
18005
18006    pub fn modify_transaction_selection_history(
18007        &mut self,
18008        transaction_id: TransactionId,
18009        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18010    ) -> bool {
18011        self.selection_history
18012            .transaction_mut(transaction_id)
18013            .map(modify)
18014            .is_some()
18015    }
18016
18017    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18018        if self.selection_mark_mode {
18019            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18020                s.move_with(|_, sel| {
18021                    sel.collapse_to(sel.head(), SelectionGoal::None);
18022                });
18023            })
18024        }
18025        self.selection_mark_mode = true;
18026        cx.notify();
18027    }
18028
18029    pub fn swap_selection_ends(
18030        &mut self,
18031        _: &actions::SwapSelectionEnds,
18032        window: &mut Window,
18033        cx: &mut Context<Self>,
18034    ) {
18035        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18036            s.move_with(|_, sel| {
18037                if sel.start != sel.end {
18038                    sel.reversed = !sel.reversed
18039                }
18040            });
18041        });
18042        self.request_autoscroll(Autoscroll::newest(), cx);
18043        cx.notify();
18044    }
18045
18046    pub fn toggle_focus(
18047        workspace: &mut Workspace,
18048        _: &actions::ToggleFocus,
18049        window: &mut Window,
18050        cx: &mut Context<Workspace>,
18051    ) {
18052        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18053            return;
18054        };
18055        workspace.activate_item(&item, true, true, window, cx);
18056    }
18057
18058    pub fn toggle_fold(
18059        &mut self,
18060        _: &actions::ToggleFold,
18061        window: &mut Window,
18062        cx: &mut Context<Self>,
18063    ) {
18064        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18065            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18066            let selection = self.selections.newest::<Point>(&display_map);
18067
18068            let range = if selection.is_empty() {
18069                let point = selection.head().to_display_point(&display_map);
18070                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18071                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18072                    .to_point(&display_map);
18073                start..end
18074            } else {
18075                selection.range()
18076            };
18077            if display_map.folds_in_range(range).next().is_some() {
18078                self.unfold_lines(&Default::default(), window, cx)
18079            } else {
18080                self.fold(&Default::default(), window, cx)
18081            }
18082        } else {
18083            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18084            let buffer_ids: HashSet<_> = self
18085                .selections
18086                .disjoint_anchor_ranges()
18087                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18088                .collect();
18089
18090            let should_unfold = buffer_ids
18091                .iter()
18092                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18093
18094            for buffer_id in buffer_ids {
18095                if should_unfold {
18096                    self.unfold_buffer(buffer_id, cx);
18097                } else {
18098                    self.fold_buffer(buffer_id, cx);
18099                }
18100            }
18101        }
18102    }
18103
18104    pub fn toggle_fold_recursive(
18105        &mut self,
18106        _: &actions::ToggleFoldRecursive,
18107        window: &mut Window,
18108        cx: &mut Context<Self>,
18109    ) {
18110        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18111
18112        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18113        let range = if selection.is_empty() {
18114            let point = selection.head().to_display_point(&display_map);
18115            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18116            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18117                .to_point(&display_map);
18118            start..end
18119        } else {
18120            selection.range()
18121        };
18122        if display_map.folds_in_range(range).next().is_some() {
18123            self.unfold_recursive(&Default::default(), window, cx)
18124        } else {
18125            self.fold_recursive(&Default::default(), window, cx)
18126        }
18127    }
18128
18129    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18130        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18131            let mut to_fold = Vec::new();
18132            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18133            let selections = self.selections.all_adjusted(&display_map);
18134
18135            for selection in selections {
18136                let range = selection.range().sorted();
18137                let buffer_start_row = range.start.row;
18138
18139                if range.start.row != range.end.row {
18140                    let mut found = false;
18141                    let mut row = range.start.row;
18142                    while row <= range.end.row {
18143                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18144                        {
18145                            found = true;
18146                            row = crease.range().end.row + 1;
18147                            to_fold.push(crease);
18148                        } else {
18149                            row += 1
18150                        }
18151                    }
18152                    if found {
18153                        continue;
18154                    }
18155                }
18156
18157                for row in (0..=range.start.row).rev() {
18158                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18159                        && crease.range().end.row >= buffer_start_row
18160                    {
18161                        to_fold.push(crease);
18162                        if row <= range.start.row {
18163                            break;
18164                        }
18165                    }
18166                }
18167            }
18168
18169            self.fold_creases(to_fold, true, window, cx);
18170        } else {
18171            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18172            let buffer_ids = self
18173                .selections
18174                .disjoint_anchor_ranges()
18175                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18176                .collect::<HashSet<_>>();
18177            for buffer_id in buffer_ids {
18178                self.fold_buffer(buffer_id, cx);
18179            }
18180        }
18181    }
18182
18183    pub fn toggle_fold_all(
18184        &mut self,
18185        _: &actions::ToggleFoldAll,
18186        window: &mut Window,
18187        cx: &mut Context<Self>,
18188    ) {
18189        if self.buffer.read(cx).is_singleton() {
18190            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18191            let has_folds = display_map
18192                .folds_in_range(0..display_map.buffer_snapshot().len())
18193                .next()
18194                .is_some();
18195
18196            if has_folds {
18197                self.unfold_all(&actions::UnfoldAll, window, cx);
18198            } else {
18199                self.fold_all(&actions::FoldAll, window, cx);
18200            }
18201        } else {
18202            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18203            let should_unfold = buffer_ids
18204                .iter()
18205                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18206
18207            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18208                editor
18209                    .update_in(cx, |editor, _, cx| {
18210                        for buffer_id in buffer_ids {
18211                            if should_unfold {
18212                                editor.unfold_buffer(buffer_id, cx);
18213                            } else {
18214                                editor.fold_buffer(buffer_id, cx);
18215                            }
18216                        }
18217                    })
18218                    .ok();
18219            });
18220        }
18221    }
18222
18223    fn fold_at_level(
18224        &mut self,
18225        fold_at: &FoldAtLevel,
18226        window: &mut Window,
18227        cx: &mut Context<Self>,
18228    ) {
18229        if !self.buffer.read(cx).is_singleton() {
18230            return;
18231        }
18232
18233        let fold_at_level = fold_at.0;
18234        let snapshot = self.buffer.read(cx).snapshot(cx);
18235        let mut to_fold = Vec::new();
18236        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18237
18238        let row_ranges_to_keep: Vec<Range<u32>> = self
18239            .selections
18240            .all::<Point>(&self.display_snapshot(cx))
18241            .into_iter()
18242            .map(|sel| sel.start.row..sel.end.row)
18243            .collect();
18244
18245        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18246            while start_row < end_row {
18247                match self
18248                    .snapshot(window, cx)
18249                    .crease_for_buffer_row(MultiBufferRow(start_row))
18250                {
18251                    Some(crease) => {
18252                        let nested_start_row = crease.range().start.row + 1;
18253                        let nested_end_row = crease.range().end.row;
18254
18255                        if current_level < fold_at_level {
18256                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18257                        } else if current_level == fold_at_level {
18258                            // Fold iff there is no selection completely contained within the fold region
18259                            if !row_ranges_to_keep.iter().any(|selection| {
18260                                selection.end >= nested_start_row
18261                                    && selection.start <= nested_end_row
18262                            }) {
18263                                to_fold.push(crease);
18264                            }
18265                        }
18266
18267                        start_row = nested_end_row + 1;
18268                    }
18269                    None => start_row += 1,
18270                }
18271            }
18272        }
18273
18274        self.fold_creases(to_fold, true, window, cx);
18275    }
18276
18277    pub fn fold_at_level_1(
18278        &mut self,
18279        _: &actions::FoldAtLevel1,
18280        window: &mut Window,
18281        cx: &mut Context<Self>,
18282    ) {
18283        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18284    }
18285
18286    pub fn fold_at_level_2(
18287        &mut self,
18288        _: &actions::FoldAtLevel2,
18289        window: &mut Window,
18290        cx: &mut Context<Self>,
18291    ) {
18292        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18293    }
18294
18295    pub fn fold_at_level_3(
18296        &mut self,
18297        _: &actions::FoldAtLevel3,
18298        window: &mut Window,
18299        cx: &mut Context<Self>,
18300    ) {
18301        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18302    }
18303
18304    pub fn fold_at_level_4(
18305        &mut self,
18306        _: &actions::FoldAtLevel4,
18307        window: &mut Window,
18308        cx: &mut Context<Self>,
18309    ) {
18310        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18311    }
18312
18313    pub fn fold_at_level_5(
18314        &mut self,
18315        _: &actions::FoldAtLevel5,
18316        window: &mut Window,
18317        cx: &mut Context<Self>,
18318    ) {
18319        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18320    }
18321
18322    pub fn fold_at_level_6(
18323        &mut self,
18324        _: &actions::FoldAtLevel6,
18325        window: &mut Window,
18326        cx: &mut Context<Self>,
18327    ) {
18328        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18329    }
18330
18331    pub fn fold_at_level_7(
18332        &mut self,
18333        _: &actions::FoldAtLevel7,
18334        window: &mut Window,
18335        cx: &mut Context<Self>,
18336    ) {
18337        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18338    }
18339
18340    pub fn fold_at_level_8(
18341        &mut self,
18342        _: &actions::FoldAtLevel8,
18343        window: &mut Window,
18344        cx: &mut Context<Self>,
18345    ) {
18346        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18347    }
18348
18349    pub fn fold_at_level_9(
18350        &mut self,
18351        _: &actions::FoldAtLevel9,
18352        window: &mut Window,
18353        cx: &mut Context<Self>,
18354    ) {
18355        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18356    }
18357
18358    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18359        if self.buffer.read(cx).is_singleton() {
18360            let mut fold_ranges = Vec::new();
18361            let snapshot = self.buffer.read(cx).snapshot(cx);
18362
18363            for row in 0..snapshot.max_row().0 {
18364                if let Some(foldable_range) = self
18365                    .snapshot(window, cx)
18366                    .crease_for_buffer_row(MultiBufferRow(row))
18367                {
18368                    fold_ranges.push(foldable_range);
18369                }
18370            }
18371
18372            self.fold_creases(fold_ranges, true, window, cx);
18373        } else {
18374            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18375                editor
18376                    .update_in(cx, |editor, _, cx| {
18377                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18378                            editor.fold_buffer(buffer_id, cx);
18379                        }
18380                    })
18381                    .ok();
18382            });
18383        }
18384    }
18385
18386    pub fn fold_function_bodies(
18387        &mut self,
18388        _: &actions::FoldFunctionBodies,
18389        window: &mut Window,
18390        cx: &mut Context<Self>,
18391    ) {
18392        let snapshot = self.buffer.read(cx).snapshot(cx);
18393
18394        let ranges = snapshot
18395            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18396            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18397            .collect::<Vec<_>>();
18398
18399        let creases = ranges
18400            .into_iter()
18401            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18402            .collect();
18403
18404        self.fold_creases(creases, true, window, cx);
18405    }
18406
18407    pub fn fold_recursive(
18408        &mut self,
18409        _: &actions::FoldRecursive,
18410        window: &mut Window,
18411        cx: &mut Context<Self>,
18412    ) {
18413        let mut to_fold = Vec::new();
18414        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18415        let selections = self.selections.all_adjusted(&display_map);
18416
18417        for selection in selections {
18418            let range = selection.range().sorted();
18419            let buffer_start_row = range.start.row;
18420
18421            if range.start.row != range.end.row {
18422                let mut found = false;
18423                for row in range.start.row..=range.end.row {
18424                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18425                        found = true;
18426                        to_fold.push(crease);
18427                    }
18428                }
18429                if found {
18430                    continue;
18431                }
18432            }
18433
18434            for row in (0..=range.start.row).rev() {
18435                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18436                    if crease.range().end.row >= buffer_start_row {
18437                        to_fold.push(crease);
18438                    } else {
18439                        break;
18440                    }
18441                }
18442            }
18443        }
18444
18445        self.fold_creases(to_fold, true, window, cx);
18446    }
18447
18448    pub fn fold_at(
18449        &mut self,
18450        buffer_row: MultiBufferRow,
18451        window: &mut Window,
18452        cx: &mut Context<Self>,
18453    ) {
18454        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18455
18456        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18457            let autoscroll = self
18458                .selections
18459                .all::<Point>(&display_map)
18460                .iter()
18461                .any(|selection| crease.range().overlaps(&selection.range()));
18462
18463            self.fold_creases(vec![crease], autoscroll, window, cx);
18464        }
18465    }
18466
18467    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18468        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18469            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18470            let buffer = display_map.buffer_snapshot();
18471            let selections = self.selections.all::<Point>(&display_map);
18472            let ranges = selections
18473                .iter()
18474                .map(|s| {
18475                    let range = s.display_range(&display_map).sorted();
18476                    let mut start = range.start.to_point(&display_map);
18477                    let mut end = range.end.to_point(&display_map);
18478                    start.column = 0;
18479                    end.column = buffer.line_len(MultiBufferRow(end.row));
18480                    start..end
18481                })
18482                .collect::<Vec<_>>();
18483
18484            self.unfold_ranges(&ranges, true, true, cx);
18485        } else {
18486            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18487            let buffer_ids = self
18488                .selections
18489                .disjoint_anchor_ranges()
18490                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18491                .collect::<HashSet<_>>();
18492            for buffer_id in buffer_ids {
18493                self.unfold_buffer(buffer_id, cx);
18494            }
18495        }
18496    }
18497
18498    pub fn unfold_recursive(
18499        &mut self,
18500        _: &UnfoldRecursive,
18501        _window: &mut Window,
18502        cx: &mut Context<Self>,
18503    ) {
18504        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18505        let selections = self.selections.all::<Point>(&display_map);
18506        let ranges = selections
18507            .iter()
18508            .map(|s| {
18509                let mut range = s.display_range(&display_map).sorted();
18510                *range.start.column_mut() = 0;
18511                *range.end.column_mut() = display_map.line_len(range.end.row());
18512                let start = range.start.to_point(&display_map);
18513                let end = range.end.to_point(&display_map);
18514                start..end
18515            })
18516            .collect::<Vec<_>>();
18517
18518        self.unfold_ranges(&ranges, true, true, cx);
18519    }
18520
18521    pub fn unfold_at(
18522        &mut self,
18523        buffer_row: MultiBufferRow,
18524        _window: &mut Window,
18525        cx: &mut Context<Self>,
18526    ) {
18527        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18528
18529        let intersection_range = Point::new(buffer_row.0, 0)
18530            ..Point::new(
18531                buffer_row.0,
18532                display_map.buffer_snapshot().line_len(buffer_row),
18533            );
18534
18535        let autoscroll = self
18536            .selections
18537            .all::<Point>(&display_map)
18538            .iter()
18539            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18540
18541        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18542    }
18543
18544    pub fn unfold_all(
18545        &mut self,
18546        _: &actions::UnfoldAll,
18547        _window: &mut Window,
18548        cx: &mut Context<Self>,
18549    ) {
18550        if self.buffer.read(cx).is_singleton() {
18551            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18552            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18553        } else {
18554            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18555                editor
18556                    .update(cx, |editor, cx| {
18557                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18558                            editor.unfold_buffer(buffer_id, cx);
18559                        }
18560                    })
18561                    .ok();
18562            });
18563        }
18564    }
18565
18566    pub fn fold_selected_ranges(
18567        &mut self,
18568        _: &FoldSelectedRanges,
18569        window: &mut Window,
18570        cx: &mut Context<Self>,
18571    ) {
18572        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18573        let selections = self.selections.all_adjusted(&display_map);
18574        let ranges = selections
18575            .into_iter()
18576            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18577            .collect::<Vec<_>>();
18578        self.fold_creases(ranges, true, window, cx);
18579    }
18580
18581    pub fn fold_ranges<T: ToOffset + Clone>(
18582        &mut self,
18583        ranges: Vec<Range<T>>,
18584        auto_scroll: bool,
18585        window: &mut Window,
18586        cx: &mut Context<Self>,
18587    ) {
18588        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18589        let ranges = ranges
18590            .into_iter()
18591            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18592            .collect::<Vec<_>>();
18593        self.fold_creases(ranges, auto_scroll, window, cx);
18594    }
18595
18596    pub fn fold_creases<T: ToOffset + Clone>(
18597        &mut self,
18598        creases: Vec<Crease<T>>,
18599        auto_scroll: bool,
18600        _window: &mut Window,
18601        cx: &mut Context<Self>,
18602    ) {
18603        if creases.is_empty() {
18604            return;
18605        }
18606
18607        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18608
18609        if auto_scroll {
18610            self.request_autoscroll(Autoscroll::fit(), cx);
18611        }
18612
18613        cx.notify();
18614
18615        self.scrollbar_marker_state.dirty = true;
18616        self.folds_did_change(cx);
18617    }
18618
18619    /// Removes any folds whose ranges intersect any of the given ranges.
18620    pub fn unfold_ranges<T: ToOffset + Clone>(
18621        &mut self,
18622        ranges: &[Range<T>],
18623        inclusive: bool,
18624        auto_scroll: bool,
18625        cx: &mut Context<Self>,
18626    ) {
18627        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18628            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18629        });
18630        self.folds_did_change(cx);
18631    }
18632
18633    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18634        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18635            return;
18636        }
18637        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18638        self.display_map.update(cx, |display_map, cx| {
18639            display_map.fold_buffers([buffer_id], cx)
18640        });
18641        cx.emit(EditorEvent::BufferFoldToggled {
18642            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18643            folded: true,
18644        });
18645        cx.notify();
18646    }
18647
18648    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18649        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18650            return;
18651        }
18652        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18653        self.display_map.update(cx, |display_map, cx| {
18654            display_map.unfold_buffers([buffer_id], cx);
18655        });
18656        cx.emit(EditorEvent::BufferFoldToggled {
18657            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18658            folded: false,
18659        });
18660        cx.notify();
18661    }
18662
18663    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18664        self.display_map.read(cx).is_buffer_folded(buffer)
18665    }
18666
18667    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18668        self.display_map.read(cx).folded_buffers()
18669    }
18670
18671    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18672        self.display_map.update(cx, |display_map, cx| {
18673            display_map.disable_header_for_buffer(buffer_id, cx);
18674        });
18675        cx.notify();
18676    }
18677
18678    /// Removes any folds with the given ranges.
18679    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18680        &mut self,
18681        ranges: &[Range<T>],
18682        type_id: TypeId,
18683        auto_scroll: bool,
18684        cx: &mut Context<Self>,
18685    ) {
18686        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18687            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18688        });
18689        self.folds_did_change(cx);
18690    }
18691
18692    fn remove_folds_with<T: ToOffset + Clone>(
18693        &mut self,
18694        ranges: &[Range<T>],
18695        auto_scroll: bool,
18696        cx: &mut Context<Self>,
18697        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18698    ) {
18699        if ranges.is_empty() {
18700            return;
18701        }
18702
18703        let mut buffers_affected = HashSet::default();
18704        let multi_buffer = self.buffer().read(cx);
18705        for range in ranges {
18706            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18707                buffers_affected.insert(buffer.read(cx).remote_id());
18708            };
18709        }
18710
18711        self.display_map.update(cx, update);
18712
18713        if auto_scroll {
18714            self.request_autoscroll(Autoscroll::fit(), cx);
18715        }
18716
18717        cx.notify();
18718        self.scrollbar_marker_state.dirty = true;
18719        self.active_indent_guides_state.dirty = true;
18720    }
18721
18722    pub fn update_renderer_widths(
18723        &mut self,
18724        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18725        cx: &mut Context<Self>,
18726    ) -> bool {
18727        self.display_map
18728            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18729    }
18730
18731    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18732        self.display_map.read(cx).fold_placeholder.clone()
18733    }
18734
18735    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18736        self.buffer.update(cx, |buffer, cx| {
18737            buffer.set_all_diff_hunks_expanded(cx);
18738        });
18739    }
18740
18741    pub fn expand_all_diff_hunks(
18742        &mut self,
18743        _: &ExpandAllDiffHunks,
18744        _window: &mut Window,
18745        cx: &mut Context<Self>,
18746    ) {
18747        self.buffer.update(cx, |buffer, cx| {
18748            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18749        });
18750    }
18751
18752    pub fn collapse_all_diff_hunks(
18753        &mut self,
18754        _: &CollapseAllDiffHunks,
18755        _window: &mut Window,
18756        cx: &mut Context<Self>,
18757    ) {
18758        self.buffer.update(cx, |buffer, cx| {
18759            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18760        });
18761    }
18762
18763    pub fn toggle_selected_diff_hunks(
18764        &mut self,
18765        _: &ToggleSelectedDiffHunks,
18766        _window: &mut Window,
18767        cx: &mut Context<Self>,
18768    ) {
18769        let ranges: Vec<_> = self
18770            .selections
18771            .disjoint_anchors()
18772            .iter()
18773            .map(|s| s.range())
18774            .collect();
18775        self.toggle_diff_hunks_in_ranges(ranges, cx);
18776    }
18777
18778    pub fn diff_hunks_in_ranges<'a>(
18779        &'a self,
18780        ranges: &'a [Range<Anchor>],
18781        buffer: &'a MultiBufferSnapshot,
18782    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18783        ranges.iter().flat_map(move |range| {
18784            let end_excerpt_id = range.end.excerpt_id;
18785            let range = range.to_point(buffer);
18786            let mut peek_end = range.end;
18787            if range.end.row < buffer.max_row().0 {
18788                peek_end = Point::new(range.end.row + 1, 0);
18789            }
18790            buffer
18791                .diff_hunks_in_range(range.start..peek_end)
18792                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18793        })
18794    }
18795
18796    pub fn has_stageable_diff_hunks_in_ranges(
18797        &self,
18798        ranges: &[Range<Anchor>],
18799        snapshot: &MultiBufferSnapshot,
18800    ) -> bool {
18801        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18802        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18803    }
18804
18805    pub fn toggle_staged_selected_diff_hunks(
18806        &mut self,
18807        _: &::git::ToggleStaged,
18808        _: &mut Window,
18809        cx: &mut Context<Self>,
18810    ) {
18811        let snapshot = self.buffer.read(cx).snapshot(cx);
18812        let ranges: Vec<_> = self
18813            .selections
18814            .disjoint_anchors()
18815            .iter()
18816            .map(|s| s.range())
18817            .collect();
18818        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18819        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18820    }
18821
18822    pub fn set_render_diff_hunk_controls(
18823        &mut self,
18824        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18825        cx: &mut Context<Self>,
18826    ) {
18827        self.render_diff_hunk_controls = render_diff_hunk_controls;
18828        cx.notify();
18829    }
18830
18831    pub fn stage_and_next(
18832        &mut self,
18833        _: &::git::StageAndNext,
18834        window: &mut Window,
18835        cx: &mut Context<Self>,
18836    ) {
18837        self.do_stage_or_unstage_and_next(true, window, cx);
18838    }
18839
18840    pub fn unstage_and_next(
18841        &mut self,
18842        _: &::git::UnstageAndNext,
18843        window: &mut Window,
18844        cx: &mut Context<Self>,
18845    ) {
18846        self.do_stage_or_unstage_and_next(false, window, cx);
18847    }
18848
18849    pub fn stage_or_unstage_diff_hunks(
18850        &mut self,
18851        stage: bool,
18852        ranges: Vec<Range<Anchor>>,
18853        cx: &mut Context<Self>,
18854    ) {
18855        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18856        cx.spawn(async move |this, cx| {
18857            task.await?;
18858            this.update(cx, |this, cx| {
18859                let snapshot = this.buffer.read(cx).snapshot(cx);
18860                let chunk_by = this
18861                    .diff_hunks_in_ranges(&ranges, &snapshot)
18862                    .chunk_by(|hunk| hunk.buffer_id);
18863                for (buffer_id, hunks) in &chunk_by {
18864                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18865                }
18866            })
18867        })
18868        .detach_and_log_err(cx);
18869    }
18870
18871    fn save_buffers_for_ranges_if_needed(
18872        &mut self,
18873        ranges: &[Range<Anchor>],
18874        cx: &mut Context<Editor>,
18875    ) -> Task<Result<()>> {
18876        let multibuffer = self.buffer.read(cx);
18877        let snapshot = multibuffer.read(cx);
18878        let buffer_ids: HashSet<_> = ranges
18879            .iter()
18880            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18881            .collect();
18882        drop(snapshot);
18883
18884        let mut buffers = HashSet::default();
18885        for buffer_id in buffer_ids {
18886            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18887                let buffer = buffer_entity.read(cx);
18888                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18889                {
18890                    buffers.insert(buffer_entity);
18891                }
18892            }
18893        }
18894
18895        if let Some(project) = &self.project {
18896            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18897        } else {
18898            Task::ready(Ok(()))
18899        }
18900    }
18901
18902    fn do_stage_or_unstage_and_next(
18903        &mut self,
18904        stage: bool,
18905        window: &mut Window,
18906        cx: &mut Context<Self>,
18907    ) {
18908        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18909
18910        if ranges.iter().any(|range| range.start != range.end) {
18911            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18912            return;
18913        }
18914
18915        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18916        let snapshot = self.snapshot(window, cx);
18917        let position = self
18918            .selections
18919            .newest::<Point>(&snapshot.display_snapshot)
18920            .head();
18921        let mut row = snapshot
18922            .buffer_snapshot()
18923            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18924            .find(|hunk| hunk.row_range.start.0 > position.row)
18925            .map(|hunk| hunk.row_range.start);
18926
18927        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18928        // Outside of the project diff editor, wrap around to the beginning.
18929        if !all_diff_hunks_expanded {
18930            row = row.or_else(|| {
18931                snapshot
18932                    .buffer_snapshot()
18933                    .diff_hunks_in_range(Point::zero()..position)
18934                    .find(|hunk| hunk.row_range.end.0 < position.row)
18935                    .map(|hunk| hunk.row_range.start)
18936            });
18937        }
18938
18939        if let Some(row) = row {
18940            let destination = Point::new(row.0, 0);
18941            let autoscroll = Autoscroll::center();
18942
18943            self.unfold_ranges(&[destination..destination], false, false, cx);
18944            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18945                s.select_ranges([destination..destination]);
18946            });
18947        }
18948    }
18949
18950    fn do_stage_or_unstage(
18951        &self,
18952        stage: bool,
18953        buffer_id: BufferId,
18954        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18955        cx: &mut App,
18956    ) -> Option<()> {
18957        let project = self.project()?;
18958        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18959        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18960        let buffer_snapshot = buffer.read(cx).snapshot();
18961        let file_exists = buffer_snapshot
18962            .file()
18963            .is_some_and(|file| file.disk_state().exists());
18964        diff.update(cx, |diff, cx| {
18965            diff.stage_or_unstage_hunks(
18966                stage,
18967                &hunks
18968                    .map(|hunk| buffer_diff::DiffHunk {
18969                        buffer_range: hunk.buffer_range,
18970                        diff_base_byte_range: hunk.diff_base_byte_range,
18971                        secondary_status: hunk.secondary_status,
18972                        range: Point::zero()..Point::zero(), // unused
18973                    })
18974                    .collect::<Vec<_>>(),
18975                &buffer_snapshot,
18976                file_exists,
18977                cx,
18978            )
18979        });
18980        None
18981    }
18982
18983    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18984        let ranges: Vec<_> = self
18985            .selections
18986            .disjoint_anchors()
18987            .iter()
18988            .map(|s| s.range())
18989            .collect();
18990        self.buffer
18991            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18992    }
18993
18994    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18995        self.buffer.update(cx, |buffer, cx| {
18996            let ranges = vec![Anchor::min()..Anchor::max()];
18997            if !buffer.all_diff_hunks_expanded()
18998                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18999            {
19000                buffer.collapse_diff_hunks(ranges, cx);
19001                true
19002            } else {
19003                false
19004            }
19005        })
19006    }
19007
19008    fn toggle_diff_hunks_in_ranges(
19009        &mut self,
19010        ranges: Vec<Range<Anchor>>,
19011        cx: &mut Context<Editor>,
19012    ) {
19013        self.buffer.update(cx, |buffer, cx| {
19014            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19015            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19016        })
19017    }
19018
19019    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19020        self.buffer.update(cx, |buffer, cx| {
19021            let snapshot = buffer.snapshot(cx);
19022            let excerpt_id = range.end.excerpt_id;
19023            let point_range = range.to_point(&snapshot);
19024            let expand = !buffer.single_hunk_is_expanded(range, cx);
19025            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19026        })
19027    }
19028
19029    pub(crate) fn apply_all_diff_hunks(
19030        &mut self,
19031        _: &ApplyAllDiffHunks,
19032        window: &mut Window,
19033        cx: &mut Context<Self>,
19034    ) {
19035        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19036
19037        let buffers = self.buffer.read(cx).all_buffers();
19038        for branch_buffer in buffers {
19039            branch_buffer.update(cx, |branch_buffer, cx| {
19040                branch_buffer.merge_into_base(Vec::new(), cx);
19041            });
19042        }
19043
19044        if let Some(project) = self.project.clone() {
19045            self.save(
19046                SaveOptions {
19047                    format: true,
19048                    autosave: false,
19049                },
19050                project,
19051                window,
19052                cx,
19053            )
19054            .detach_and_log_err(cx);
19055        }
19056    }
19057
19058    pub(crate) fn apply_selected_diff_hunks(
19059        &mut self,
19060        _: &ApplyDiffHunk,
19061        window: &mut Window,
19062        cx: &mut Context<Self>,
19063    ) {
19064        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19065        let snapshot = self.snapshot(window, cx);
19066        let hunks = snapshot.hunks_for_ranges(
19067            self.selections
19068                .all(&snapshot.display_snapshot)
19069                .into_iter()
19070                .map(|selection| selection.range()),
19071        );
19072        let mut ranges_by_buffer = HashMap::default();
19073        self.transact(window, cx, |editor, _window, cx| {
19074            for hunk in hunks {
19075                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19076                    ranges_by_buffer
19077                        .entry(buffer.clone())
19078                        .or_insert_with(Vec::new)
19079                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19080                }
19081            }
19082
19083            for (buffer, ranges) in ranges_by_buffer {
19084                buffer.update(cx, |buffer, cx| {
19085                    buffer.merge_into_base(ranges, cx);
19086                });
19087            }
19088        });
19089
19090        if let Some(project) = self.project.clone() {
19091            self.save(
19092                SaveOptions {
19093                    format: true,
19094                    autosave: false,
19095                },
19096                project,
19097                window,
19098                cx,
19099            )
19100            .detach_and_log_err(cx);
19101        }
19102    }
19103
19104    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19105        if hovered != self.gutter_hovered {
19106            self.gutter_hovered = hovered;
19107            cx.notify();
19108        }
19109    }
19110
19111    pub fn insert_blocks(
19112        &mut self,
19113        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19114        autoscroll: Option<Autoscroll>,
19115        cx: &mut Context<Self>,
19116    ) -> Vec<CustomBlockId> {
19117        let blocks = self
19118            .display_map
19119            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19120        if let Some(autoscroll) = autoscroll {
19121            self.request_autoscroll(autoscroll, cx);
19122        }
19123        cx.notify();
19124        blocks
19125    }
19126
19127    pub fn resize_blocks(
19128        &mut self,
19129        heights: HashMap<CustomBlockId, u32>,
19130        autoscroll: Option<Autoscroll>,
19131        cx: &mut Context<Self>,
19132    ) {
19133        self.display_map
19134            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19135        if let Some(autoscroll) = autoscroll {
19136            self.request_autoscroll(autoscroll, cx);
19137        }
19138        cx.notify();
19139    }
19140
19141    pub fn replace_blocks(
19142        &mut self,
19143        renderers: HashMap<CustomBlockId, RenderBlock>,
19144        autoscroll: Option<Autoscroll>,
19145        cx: &mut Context<Self>,
19146    ) {
19147        self.display_map
19148            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19149        if let Some(autoscroll) = autoscroll {
19150            self.request_autoscroll(autoscroll, cx);
19151        }
19152        cx.notify();
19153    }
19154
19155    pub fn remove_blocks(
19156        &mut self,
19157        block_ids: HashSet<CustomBlockId>,
19158        autoscroll: Option<Autoscroll>,
19159        cx: &mut Context<Self>,
19160    ) {
19161        self.display_map.update(cx, |display_map, cx| {
19162            display_map.remove_blocks(block_ids, cx)
19163        });
19164        if let Some(autoscroll) = autoscroll {
19165            self.request_autoscroll(autoscroll, cx);
19166        }
19167        cx.notify();
19168    }
19169
19170    pub fn row_for_block(
19171        &self,
19172        block_id: CustomBlockId,
19173        cx: &mut Context<Self>,
19174    ) -> Option<DisplayRow> {
19175        self.display_map
19176            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19177    }
19178
19179    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19180        self.focused_block = Some(focused_block);
19181    }
19182
19183    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19184        self.focused_block.take()
19185    }
19186
19187    pub fn insert_creases(
19188        &mut self,
19189        creases: impl IntoIterator<Item = Crease<Anchor>>,
19190        cx: &mut Context<Self>,
19191    ) -> Vec<CreaseId> {
19192        self.display_map
19193            .update(cx, |map, cx| map.insert_creases(creases, cx))
19194    }
19195
19196    pub fn remove_creases(
19197        &mut self,
19198        ids: impl IntoIterator<Item = CreaseId>,
19199        cx: &mut Context<Self>,
19200    ) -> Vec<(CreaseId, Range<Anchor>)> {
19201        self.display_map
19202            .update(cx, |map, cx| map.remove_creases(ids, cx))
19203    }
19204
19205    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19206        self.display_map
19207            .update(cx, |map, cx| map.snapshot(cx))
19208            .longest_row()
19209    }
19210
19211    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19212        self.display_map
19213            .update(cx, |map, cx| map.snapshot(cx))
19214            .max_point()
19215    }
19216
19217    pub fn text(&self, cx: &App) -> String {
19218        self.buffer.read(cx).read(cx).text()
19219    }
19220
19221    pub fn is_empty(&self, cx: &App) -> bool {
19222        self.buffer.read(cx).read(cx).is_empty()
19223    }
19224
19225    pub fn text_option(&self, cx: &App) -> Option<String> {
19226        let text = self.text(cx);
19227        let text = text.trim();
19228
19229        if text.is_empty() {
19230            return None;
19231        }
19232
19233        Some(text.to_string())
19234    }
19235
19236    pub fn set_text(
19237        &mut self,
19238        text: impl Into<Arc<str>>,
19239        window: &mut Window,
19240        cx: &mut Context<Self>,
19241    ) {
19242        self.transact(window, cx, |this, _, cx| {
19243            this.buffer
19244                .read(cx)
19245                .as_singleton()
19246                .expect("you can only call set_text on editors for singleton buffers")
19247                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19248        });
19249    }
19250
19251    pub fn display_text(&self, cx: &mut App) -> String {
19252        self.display_map
19253            .update(cx, |map, cx| map.snapshot(cx))
19254            .text()
19255    }
19256
19257    fn create_minimap(
19258        &self,
19259        minimap_settings: MinimapSettings,
19260        window: &mut Window,
19261        cx: &mut Context<Self>,
19262    ) -> Option<Entity<Self>> {
19263        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19264            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19265    }
19266
19267    fn initialize_new_minimap(
19268        &self,
19269        minimap_settings: MinimapSettings,
19270        window: &mut Window,
19271        cx: &mut Context<Self>,
19272    ) -> Entity<Self> {
19273        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19274
19275        let mut minimap = Editor::new_internal(
19276            EditorMode::Minimap {
19277                parent: cx.weak_entity(),
19278            },
19279            self.buffer.clone(),
19280            None,
19281            Some(self.display_map.clone()),
19282            window,
19283            cx,
19284        );
19285        minimap.scroll_manager.clone_state(&self.scroll_manager);
19286        minimap.set_text_style_refinement(TextStyleRefinement {
19287            font_size: Some(MINIMAP_FONT_SIZE),
19288            font_weight: Some(MINIMAP_FONT_WEIGHT),
19289            ..Default::default()
19290        });
19291        minimap.update_minimap_configuration(minimap_settings, cx);
19292        cx.new(|_| minimap)
19293    }
19294
19295    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19296        let current_line_highlight = minimap_settings
19297            .current_line_highlight
19298            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19299        self.set_current_line_highlight(Some(current_line_highlight));
19300    }
19301
19302    pub fn minimap(&self) -> Option<&Entity<Self>> {
19303        self.minimap
19304            .as_ref()
19305            .filter(|_| self.minimap_visibility.visible())
19306    }
19307
19308    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19309        let mut wrap_guides = smallvec![];
19310
19311        if self.show_wrap_guides == Some(false) {
19312            return wrap_guides;
19313        }
19314
19315        let settings = self.buffer.read(cx).language_settings(cx);
19316        if settings.show_wrap_guides {
19317            match self.soft_wrap_mode(cx) {
19318                SoftWrap::Column(soft_wrap) => {
19319                    wrap_guides.push((soft_wrap as usize, true));
19320                }
19321                SoftWrap::Bounded(soft_wrap) => {
19322                    wrap_guides.push((soft_wrap as usize, true));
19323                }
19324                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19325            }
19326            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19327        }
19328
19329        wrap_guides
19330    }
19331
19332    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19333        let settings = self.buffer.read(cx).language_settings(cx);
19334        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19335        match mode {
19336            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19337                SoftWrap::None
19338            }
19339            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19340            language_settings::SoftWrap::PreferredLineLength => {
19341                SoftWrap::Column(settings.preferred_line_length)
19342            }
19343            language_settings::SoftWrap::Bounded => {
19344                SoftWrap::Bounded(settings.preferred_line_length)
19345            }
19346        }
19347    }
19348
19349    pub fn set_soft_wrap_mode(
19350        &mut self,
19351        mode: language_settings::SoftWrap,
19352
19353        cx: &mut Context<Self>,
19354    ) {
19355        self.soft_wrap_mode_override = Some(mode);
19356        cx.notify();
19357    }
19358
19359    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19360        self.hard_wrap = hard_wrap;
19361        cx.notify();
19362    }
19363
19364    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19365        self.text_style_refinement = Some(style);
19366    }
19367
19368    /// called by the Element so we know what style we were most recently rendered with.
19369    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19370        // We intentionally do not inform the display map about the minimap style
19371        // so that wrapping is not recalculated and stays consistent for the editor
19372        // and its linked minimap.
19373        if !self.mode.is_minimap() {
19374            let font = style.text.font();
19375            let font_size = style.text.font_size.to_pixels(window.rem_size());
19376            let display_map = self
19377                .placeholder_display_map
19378                .as_ref()
19379                .filter(|_| self.is_empty(cx))
19380                .unwrap_or(&self.display_map);
19381
19382            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19383        }
19384        self.style = Some(style);
19385    }
19386
19387    pub fn style(&self) -> Option<&EditorStyle> {
19388        self.style.as_ref()
19389    }
19390
19391    // Called by the element. This method is not designed to be called outside of the editor
19392    // element's layout code because it does not notify when rewrapping is computed synchronously.
19393    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19394        if self.is_empty(cx) {
19395            self.placeholder_display_map
19396                .as_ref()
19397                .map_or(false, |display_map| {
19398                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19399                })
19400        } else {
19401            self.display_map
19402                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19403        }
19404    }
19405
19406    pub fn set_soft_wrap(&mut self) {
19407        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19408    }
19409
19410    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19411        if self.soft_wrap_mode_override.is_some() {
19412            self.soft_wrap_mode_override.take();
19413        } else {
19414            let soft_wrap = match self.soft_wrap_mode(cx) {
19415                SoftWrap::GitDiff => return,
19416                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19417                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19418                    language_settings::SoftWrap::None
19419                }
19420            };
19421            self.soft_wrap_mode_override = Some(soft_wrap);
19422        }
19423        cx.notify();
19424    }
19425
19426    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19427        let Some(workspace) = self.workspace() else {
19428            return;
19429        };
19430        let fs = workspace.read(cx).app_state().fs.clone();
19431        let current_show = TabBarSettings::get_global(cx).show;
19432        update_settings_file(fs, cx, move |setting, _| {
19433            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19434        });
19435    }
19436
19437    pub fn toggle_indent_guides(
19438        &mut self,
19439        _: &ToggleIndentGuides,
19440        _: &mut Window,
19441        cx: &mut Context<Self>,
19442    ) {
19443        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19444            self.buffer
19445                .read(cx)
19446                .language_settings(cx)
19447                .indent_guides
19448                .enabled
19449        });
19450        self.show_indent_guides = Some(!currently_enabled);
19451        cx.notify();
19452    }
19453
19454    fn should_show_indent_guides(&self) -> Option<bool> {
19455        self.show_indent_guides
19456    }
19457
19458    pub fn toggle_line_numbers(
19459        &mut self,
19460        _: &ToggleLineNumbers,
19461        _: &mut Window,
19462        cx: &mut Context<Self>,
19463    ) {
19464        let mut editor_settings = EditorSettings::get_global(cx).clone();
19465        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19466        EditorSettings::override_global(editor_settings, cx);
19467    }
19468
19469    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19470        if let Some(show_line_numbers) = self.show_line_numbers {
19471            return show_line_numbers;
19472        }
19473        EditorSettings::get_global(cx).gutter.line_numbers
19474    }
19475
19476    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19477        self.use_relative_line_numbers
19478            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19479    }
19480
19481    pub fn toggle_relative_line_numbers(
19482        &mut self,
19483        _: &ToggleRelativeLineNumbers,
19484        _: &mut Window,
19485        cx: &mut Context<Self>,
19486    ) {
19487        let is_relative = self.should_use_relative_line_numbers(cx);
19488        self.set_relative_line_number(Some(!is_relative), cx)
19489    }
19490
19491    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19492        self.use_relative_line_numbers = is_relative;
19493        cx.notify();
19494    }
19495
19496    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19497        self.show_gutter = show_gutter;
19498        cx.notify();
19499    }
19500
19501    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19502        self.show_scrollbars = ScrollbarAxes {
19503            horizontal: show,
19504            vertical: show,
19505        };
19506        cx.notify();
19507    }
19508
19509    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19510        self.show_scrollbars.vertical = show;
19511        cx.notify();
19512    }
19513
19514    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19515        self.show_scrollbars.horizontal = show;
19516        cx.notify();
19517    }
19518
19519    pub fn set_minimap_visibility(
19520        &mut self,
19521        minimap_visibility: MinimapVisibility,
19522        window: &mut Window,
19523        cx: &mut Context<Self>,
19524    ) {
19525        if self.minimap_visibility != minimap_visibility {
19526            if minimap_visibility.visible() && self.minimap.is_none() {
19527                let minimap_settings = EditorSettings::get_global(cx).minimap;
19528                self.minimap =
19529                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19530            }
19531            self.minimap_visibility = minimap_visibility;
19532            cx.notify();
19533        }
19534    }
19535
19536    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19537        self.set_show_scrollbars(false, cx);
19538        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19539    }
19540
19541    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19542        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19543    }
19544
19545    /// Normally the text in full mode and auto height editors is padded on the
19546    /// left side by roughly half a character width for improved hit testing.
19547    ///
19548    /// Use this method to disable this for cases where this is not wanted (e.g.
19549    /// if you want to align the editor text with some other text above or below)
19550    /// or if you want to add this padding to single-line editors.
19551    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19552        self.offset_content = offset_content;
19553        cx.notify();
19554    }
19555
19556    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19557        self.show_line_numbers = Some(show_line_numbers);
19558        cx.notify();
19559    }
19560
19561    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19562        self.disable_expand_excerpt_buttons = true;
19563        cx.notify();
19564    }
19565
19566    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19567        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19568        cx.notify();
19569    }
19570
19571    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19572        self.show_code_actions = Some(show_code_actions);
19573        cx.notify();
19574    }
19575
19576    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19577        self.show_runnables = Some(show_runnables);
19578        cx.notify();
19579    }
19580
19581    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19582        self.show_breakpoints = Some(show_breakpoints);
19583        cx.notify();
19584    }
19585
19586    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19587        if self.display_map.read(cx).masked != masked {
19588            self.display_map.update(cx, |map, _| map.masked = masked);
19589        }
19590        cx.notify()
19591    }
19592
19593    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19594        self.show_wrap_guides = Some(show_wrap_guides);
19595        cx.notify();
19596    }
19597
19598    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19599        self.show_indent_guides = Some(show_indent_guides);
19600        cx.notify();
19601    }
19602
19603    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19604        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19605            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19606                && let Some(dir) = file.abs_path(cx).parent()
19607            {
19608                return Some(dir.to_owned());
19609            }
19610        }
19611
19612        None
19613    }
19614
19615    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19616        self.active_excerpt(cx)?
19617            .1
19618            .read(cx)
19619            .file()
19620            .and_then(|f| f.as_local())
19621    }
19622
19623    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19624        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19625            let buffer = buffer.read(cx);
19626            if let Some(project_path) = buffer.project_path(cx) {
19627                let project = self.project()?.read(cx);
19628                project.absolute_path(&project_path, cx)
19629            } else {
19630                buffer
19631                    .file()
19632                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19633            }
19634        })
19635    }
19636
19637    pub fn reveal_in_finder(
19638        &mut self,
19639        _: &RevealInFileManager,
19640        _window: &mut Window,
19641        cx: &mut Context<Self>,
19642    ) {
19643        if let Some(target) = self.target_file(cx) {
19644            cx.reveal_path(&target.abs_path(cx));
19645        }
19646    }
19647
19648    pub fn copy_path(
19649        &mut self,
19650        _: &zed_actions::workspace::CopyPath,
19651        _window: &mut Window,
19652        cx: &mut Context<Self>,
19653    ) {
19654        if let Some(path) = self.target_file_abs_path(cx)
19655            && let Some(path) = path.to_str()
19656        {
19657            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19658        } else {
19659            cx.propagate();
19660        }
19661    }
19662
19663    pub fn copy_relative_path(
19664        &mut self,
19665        _: &zed_actions::workspace::CopyRelativePath,
19666        _window: &mut Window,
19667        cx: &mut Context<Self>,
19668    ) {
19669        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19670            let project = self.project()?.read(cx);
19671            let path = buffer.read(cx).file()?.path();
19672            let path = path.display(project.path_style(cx));
19673            Some(path)
19674        }) {
19675            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19676        } else {
19677            cx.propagate();
19678        }
19679    }
19680
19681    /// Returns the project path for the editor's buffer, if any buffer is
19682    /// opened in the editor.
19683    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19684        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19685            buffer.read(cx).project_path(cx)
19686        } else {
19687            None
19688        }
19689    }
19690
19691    // Returns true if the editor handled a go-to-line request
19692    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19693        maybe!({
19694            let breakpoint_store = self.breakpoint_store.as_ref()?;
19695
19696            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19697            else {
19698                self.clear_row_highlights::<ActiveDebugLine>();
19699                return None;
19700            };
19701
19702            let position = active_stack_frame.position;
19703            let buffer_id = position.buffer_id?;
19704            let snapshot = self
19705                .project
19706                .as_ref()?
19707                .read(cx)
19708                .buffer_for_id(buffer_id, cx)?
19709                .read(cx)
19710                .snapshot();
19711
19712            let mut handled = false;
19713            for (id, ExcerptRange { context, .. }) in
19714                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19715            {
19716                if context.start.cmp(&position, &snapshot).is_ge()
19717                    || context.end.cmp(&position, &snapshot).is_lt()
19718                {
19719                    continue;
19720                }
19721                let snapshot = self.buffer.read(cx).snapshot(cx);
19722                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19723
19724                handled = true;
19725                self.clear_row_highlights::<ActiveDebugLine>();
19726
19727                self.go_to_line::<ActiveDebugLine>(
19728                    multibuffer_anchor,
19729                    Some(cx.theme().colors().editor_debugger_active_line_background),
19730                    window,
19731                    cx,
19732                );
19733
19734                cx.notify();
19735            }
19736
19737            handled.then_some(())
19738        })
19739        .is_some()
19740    }
19741
19742    pub fn copy_file_name_without_extension(
19743        &mut self,
19744        _: &CopyFileNameWithoutExtension,
19745        _: &mut Window,
19746        cx: &mut Context<Self>,
19747    ) {
19748        if let Some(file) = self.target_file(cx)
19749            && let Some(file_stem) = file.path().file_stem()
19750        {
19751            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19752        }
19753    }
19754
19755    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19756        if let Some(file) = self.target_file(cx)
19757            && let Some(name) = file.path().file_name()
19758        {
19759            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19760        }
19761    }
19762
19763    pub fn toggle_git_blame(
19764        &mut self,
19765        _: &::git::Blame,
19766        window: &mut Window,
19767        cx: &mut Context<Self>,
19768    ) {
19769        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19770
19771        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19772            self.start_git_blame(true, window, cx);
19773        }
19774
19775        cx.notify();
19776    }
19777
19778    pub fn toggle_git_blame_inline(
19779        &mut self,
19780        _: &ToggleGitBlameInline,
19781        window: &mut Window,
19782        cx: &mut Context<Self>,
19783    ) {
19784        self.toggle_git_blame_inline_internal(true, window, cx);
19785        cx.notify();
19786    }
19787
19788    pub fn open_git_blame_commit(
19789        &mut self,
19790        _: &OpenGitBlameCommit,
19791        window: &mut Window,
19792        cx: &mut Context<Self>,
19793    ) {
19794        self.open_git_blame_commit_internal(window, cx);
19795    }
19796
19797    fn open_git_blame_commit_internal(
19798        &mut self,
19799        window: &mut Window,
19800        cx: &mut Context<Self>,
19801    ) -> Option<()> {
19802        let blame = self.blame.as_ref()?;
19803        let snapshot = self.snapshot(window, cx);
19804        let cursor = self
19805            .selections
19806            .newest::<Point>(&snapshot.display_snapshot)
19807            .head();
19808        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19809        let (_, blame_entry) = blame
19810            .update(cx, |blame, cx| {
19811                blame
19812                    .blame_for_rows(
19813                        &[RowInfo {
19814                            buffer_id: Some(buffer.remote_id()),
19815                            buffer_row: Some(point.row),
19816                            ..Default::default()
19817                        }],
19818                        cx,
19819                    )
19820                    .next()
19821            })
19822            .flatten()?;
19823        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19824        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19825        let workspace = self.workspace()?.downgrade();
19826        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19827        None
19828    }
19829
19830    pub fn git_blame_inline_enabled(&self) -> bool {
19831        self.git_blame_inline_enabled
19832    }
19833
19834    pub fn toggle_selection_menu(
19835        &mut self,
19836        _: &ToggleSelectionMenu,
19837        _: &mut Window,
19838        cx: &mut Context<Self>,
19839    ) {
19840        self.show_selection_menu = self
19841            .show_selection_menu
19842            .map(|show_selections_menu| !show_selections_menu)
19843            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19844
19845        cx.notify();
19846    }
19847
19848    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19849        self.show_selection_menu
19850            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19851    }
19852
19853    fn start_git_blame(
19854        &mut self,
19855        user_triggered: bool,
19856        window: &mut Window,
19857        cx: &mut Context<Self>,
19858    ) {
19859        if let Some(project) = self.project() {
19860            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19861                && buffer.read(cx).file().is_none()
19862            {
19863                return;
19864            }
19865
19866            let focused = self.focus_handle(cx).contains_focused(window, cx);
19867
19868            let project = project.clone();
19869            let blame = cx
19870                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19871            self.blame_subscription =
19872                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19873            self.blame = Some(blame);
19874        }
19875    }
19876
19877    fn toggle_git_blame_inline_internal(
19878        &mut self,
19879        user_triggered: bool,
19880        window: &mut Window,
19881        cx: &mut Context<Self>,
19882    ) {
19883        if self.git_blame_inline_enabled {
19884            self.git_blame_inline_enabled = false;
19885            self.show_git_blame_inline = false;
19886            self.show_git_blame_inline_delay_task.take();
19887        } else {
19888            self.git_blame_inline_enabled = true;
19889            self.start_git_blame_inline(user_triggered, window, cx);
19890        }
19891
19892        cx.notify();
19893    }
19894
19895    fn start_git_blame_inline(
19896        &mut self,
19897        user_triggered: bool,
19898        window: &mut Window,
19899        cx: &mut Context<Self>,
19900    ) {
19901        self.start_git_blame(user_triggered, window, cx);
19902
19903        if ProjectSettings::get_global(cx)
19904            .git
19905            .inline_blame_delay()
19906            .is_some()
19907        {
19908            self.start_inline_blame_timer(window, cx);
19909        } else {
19910            self.show_git_blame_inline = true
19911        }
19912    }
19913
19914    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19915        self.blame.as_ref()
19916    }
19917
19918    pub fn show_git_blame_gutter(&self) -> bool {
19919        self.show_git_blame_gutter
19920    }
19921
19922    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19923        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19924    }
19925
19926    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19927        self.show_git_blame_inline
19928            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19929            && !self.newest_selection_head_on_empty_line(cx)
19930            && self.has_blame_entries(cx)
19931    }
19932
19933    fn has_blame_entries(&self, cx: &App) -> bool {
19934        self.blame()
19935            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19936    }
19937
19938    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19939        let cursor_anchor = self.selections.newest_anchor().head();
19940
19941        let snapshot = self.buffer.read(cx).snapshot(cx);
19942        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19943
19944        snapshot.line_len(buffer_row) == 0
19945    }
19946
19947    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19948        let buffer_and_selection = maybe!({
19949            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19950            let selection_range = selection.range();
19951
19952            let multi_buffer = self.buffer().read(cx);
19953            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19954            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19955
19956            let (buffer, range, _) = if selection.reversed {
19957                buffer_ranges.first()
19958            } else {
19959                buffer_ranges.last()
19960            }?;
19961
19962            let selection = text::ToPoint::to_point(&range.start, buffer).row
19963                ..text::ToPoint::to_point(&range.end, buffer).row;
19964            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19965        });
19966
19967        let Some((buffer, selection)) = buffer_and_selection else {
19968            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19969        };
19970
19971        let Some(project) = self.project() else {
19972            return Task::ready(Err(anyhow!("editor does not have project")));
19973        };
19974
19975        project.update(cx, |project, cx| {
19976            project.get_permalink_to_line(&buffer, selection, cx)
19977        })
19978    }
19979
19980    pub fn copy_permalink_to_line(
19981        &mut self,
19982        _: &CopyPermalinkToLine,
19983        window: &mut Window,
19984        cx: &mut Context<Self>,
19985    ) {
19986        let permalink_task = self.get_permalink_to_line(cx);
19987        let workspace = self.workspace();
19988
19989        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19990            Ok(permalink) => {
19991                cx.update(|_, cx| {
19992                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19993                })
19994                .ok();
19995            }
19996            Err(err) => {
19997                let message = format!("Failed to copy permalink: {err}");
19998
19999                anyhow::Result::<()>::Err(err).log_err();
20000
20001                if let Some(workspace) = workspace {
20002                    workspace
20003                        .update_in(cx, |workspace, _, cx| {
20004                            struct CopyPermalinkToLine;
20005
20006                            workspace.show_toast(
20007                                Toast::new(
20008                                    NotificationId::unique::<CopyPermalinkToLine>(),
20009                                    message,
20010                                ),
20011                                cx,
20012                            )
20013                        })
20014                        .ok();
20015                }
20016            }
20017        })
20018        .detach();
20019    }
20020
20021    pub fn copy_file_location(
20022        &mut self,
20023        _: &CopyFileLocation,
20024        _: &mut Window,
20025        cx: &mut Context<Self>,
20026    ) {
20027        let selection = self
20028            .selections
20029            .newest::<Point>(&self.display_snapshot(cx))
20030            .start
20031            .row
20032            + 1;
20033        if let Some(file) = self.target_file(cx) {
20034            let path = file.path().display(file.path_style(cx));
20035            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20036        }
20037    }
20038
20039    pub fn open_permalink_to_line(
20040        &mut self,
20041        _: &OpenPermalinkToLine,
20042        window: &mut Window,
20043        cx: &mut Context<Self>,
20044    ) {
20045        let permalink_task = self.get_permalink_to_line(cx);
20046        let workspace = self.workspace();
20047
20048        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20049            Ok(permalink) => {
20050                cx.update(|_, cx| {
20051                    cx.open_url(permalink.as_ref());
20052                })
20053                .ok();
20054            }
20055            Err(err) => {
20056                let message = format!("Failed to open permalink: {err}");
20057
20058                anyhow::Result::<()>::Err(err).log_err();
20059
20060                if let Some(workspace) = workspace {
20061                    workspace
20062                        .update(cx, |workspace, cx| {
20063                            struct OpenPermalinkToLine;
20064
20065                            workspace.show_toast(
20066                                Toast::new(
20067                                    NotificationId::unique::<OpenPermalinkToLine>(),
20068                                    message,
20069                                ),
20070                                cx,
20071                            )
20072                        })
20073                        .ok();
20074                }
20075            }
20076        })
20077        .detach();
20078    }
20079
20080    pub fn insert_uuid_v4(
20081        &mut self,
20082        _: &InsertUuidV4,
20083        window: &mut Window,
20084        cx: &mut Context<Self>,
20085    ) {
20086        self.insert_uuid(UuidVersion::V4, window, cx);
20087    }
20088
20089    pub fn insert_uuid_v7(
20090        &mut self,
20091        _: &InsertUuidV7,
20092        window: &mut Window,
20093        cx: &mut Context<Self>,
20094    ) {
20095        self.insert_uuid(UuidVersion::V7, window, cx);
20096    }
20097
20098    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20099        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20100        self.transact(window, cx, |this, window, cx| {
20101            let edits = this
20102                .selections
20103                .all::<Point>(&this.display_snapshot(cx))
20104                .into_iter()
20105                .map(|selection| {
20106                    let uuid = match version {
20107                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20108                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20109                    };
20110
20111                    (selection.range(), uuid.to_string())
20112                });
20113            this.edit(edits, cx);
20114            this.refresh_edit_prediction(true, false, window, cx);
20115        });
20116    }
20117
20118    pub fn open_selections_in_multibuffer(
20119        &mut self,
20120        _: &OpenSelectionsInMultibuffer,
20121        window: &mut Window,
20122        cx: &mut Context<Self>,
20123    ) {
20124        let multibuffer = self.buffer.read(cx);
20125
20126        let Some(buffer) = multibuffer.as_singleton() else {
20127            return;
20128        };
20129
20130        let Some(workspace) = self.workspace() else {
20131            return;
20132        };
20133
20134        let title = multibuffer.title(cx).to_string();
20135
20136        let locations = self
20137            .selections
20138            .all_anchors(cx)
20139            .iter()
20140            .map(|selection| {
20141                (
20142                    buffer.clone(),
20143                    (selection.start.text_anchor..selection.end.text_anchor)
20144                        .to_point(buffer.read(cx)),
20145                )
20146            })
20147            .into_group_map();
20148
20149        cx.spawn_in(window, async move |_, cx| {
20150            workspace.update_in(cx, |workspace, window, cx| {
20151                Self::open_locations_in_multibuffer(
20152                    workspace,
20153                    locations,
20154                    format!("Selections for '{title}'"),
20155                    false,
20156                    MultibufferSelectionMode::All,
20157                    window,
20158                    cx,
20159                );
20160            })
20161        })
20162        .detach();
20163    }
20164
20165    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20166    /// last highlight added will be used.
20167    ///
20168    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20169    pub fn highlight_rows<T: 'static>(
20170        &mut self,
20171        range: Range<Anchor>,
20172        color: Hsla,
20173        options: RowHighlightOptions,
20174        cx: &mut Context<Self>,
20175    ) {
20176        let snapshot = self.buffer().read(cx).snapshot(cx);
20177        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20178        let ix = row_highlights.binary_search_by(|highlight| {
20179            Ordering::Equal
20180                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20181                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20182        });
20183
20184        if let Err(mut ix) = ix {
20185            let index = post_inc(&mut self.highlight_order);
20186
20187            // If this range intersects with the preceding highlight, then merge it with
20188            // the preceding highlight. Otherwise insert a new highlight.
20189            let mut merged = false;
20190            if ix > 0 {
20191                let prev_highlight = &mut row_highlights[ix - 1];
20192                if prev_highlight
20193                    .range
20194                    .end
20195                    .cmp(&range.start, &snapshot)
20196                    .is_ge()
20197                {
20198                    ix -= 1;
20199                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20200                        prev_highlight.range.end = range.end;
20201                    }
20202                    merged = true;
20203                    prev_highlight.index = index;
20204                    prev_highlight.color = color;
20205                    prev_highlight.options = options;
20206                }
20207            }
20208
20209            if !merged {
20210                row_highlights.insert(
20211                    ix,
20212                    RowHighlight {
20213                        range,
20214                        index,
20215                        color,
20216                        options,
20217                        type_id: TypeId::of::<T>(),
20218                    },
20219                );
20220            }
20221
20222            // If any of the following highlights intersect with this one, merge them.
20223            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20224                let highlight = &row_highlights[ix];
20225                if next_highlight
20226                    .range
20227                    .start
20228                    .cmp(&highlight.range.end, &snapshot)
20229                    .is_le()
20230                {
20231                    if next_highlight
20232                        .range
20233                        .end
20234                        .cmp(&highlight.range.end, &snapshot)
20235                        .is_gt()
20236                    {
20237                        row_highlights[ix].range.end = next_highlight.range.end;
20238                    }
20239                    row_highlights.remove(ix + 1);
20240                } else {
20241                    break;
20242                }
20243            }
20244        }
20245    }
20246
20247    /// Remove any highlighted row ranges of the given type that intersect the
20248    /// given ranges.
20249    pub fn remove_highlighted_rows<T: 'static>(
20250        &mut self,
20251        ranges_to_remove: Vec<Range<Anchor>>,
20252        cx: &mut Context<Self>,
20253    ) {
20254        let snapshot = self.buffer().read(cx).snapshot(cx);
20255        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20256        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20257        row_highlights.retain(|highlight| {
20258            while let Some(range_to_remove) = ranges_to_remove.peek() {
20259                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20260                    Ordering::Less | Ordering::Equal => {
20261                        ranges_to_remove.next();
20262                    }
20263                    Ordering::Greater => {
20264                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20265                            Ordering::Less | Ordering::Equal => {
20266                                return false;
20267                            }
20268                            Ordering::Greater => break,
20269                        }
20270                    }
20271                }
20272            }
20273
20274            true
20275        })
20276    }
20277
20278    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20279    pub fn clear_row_highlights<T: 'static>(&mut self) {
20280        self.highlighted_rows.remove(&TypeId::of::<T>());
20281    }
20282
20283    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20284    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20285        self.highlighted_rows
20286            .get(&TypeId::of::<T>())
20287            .map_or(&[] as &[_], |vec| vec.as_slice())
20288            .iter()
20289            .map(|highlight| (highlight.range.clone(), highlight.color))
20290    }
20291
20292    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20293    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20294    /// Allows to ignore certain kinds of highlights.
20295    pub fn highlighted_display_rows(
20296        &self,
20297        window: &mut Window,
20298        cx: &mut App,
20299    ) -> BTreeMap<DisplayRow, LineHighlight> {
20300        let snapshot = self.snapshot(window, cx);
20301        let mut used_highlight_orders = HashMap::default();
20302        self.highlighted_rows
20303            .iter()
20304            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20305            .fold(
20306                BTreeMap::<DisplayRow, LineHighlight>::new(),
20307                |mut unique_rows, highlight| {
20308                    let start = highlight.range.start.to_display_point(&snapshot);
20309                    let end = highlight.range.end.to_display_point(&snapshot);
20310                    let start_row = start.row().0;
20311                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20312                        && end.column() == 0
20313                    {
20314                        end.row().0.saturating_sub(1)
20315                    } else {
20316                        end.row().0
20317                    };
20318                    for row in start_row..=end_row {
20319                        let used_index =
20320                            used_highlight_orders.entry(row).or_insert(highlight.index);
20321                        if highlight.index >= *used_index {
20322                            *used_index = highlight.index;
20323                            unique_rows.insert(
20324                                DisplayRow(row),
20325                                LineHighlight {
20326                                    include_gutter: highlight.options.include_gutter,
20327                                    border: None,
20328                                    background: highlight.color.into(),
20329                                    type_id: Some(highlight.type_id),
20330                                },
20331                            );
20332                        }
20333                    }
20334                    unique_rows
20335                },
20336            )
20337    }
20338
20339    pub fn highlighted_display_row_for_autoscroll(
20340        &self,
20341        snapshot: &DisplaySnapshot,
20342    ) -> Option<DisplayRow> {
20343        self.highlighted_rows
20344            .values()
20345            .flat_map(|highlighted_rows| highlighted_rows.iter())
20346            .filter_map(|highlight| {
20347                if highlight.options.autoscroll {
20348                    Some(highlight.range.start.to_display_point(snapshot).row())
20349                } else {
20350                    None
20351                }
20352            })
20353            .min()
20354    }
20355
20356    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20357        self.highlight_background::<SearchWithinRange>(
20358            ranges,
20359            |colors| colors.colors().editor_document_highlight_read_background,
20360            cx,
20361        )
20362    }
20363
20364    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20365        self.breadcrumb_header = Some(new_header);
20366    }
20367
20368    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20369        self.clear_background_highlights::<SearchWithinRange>(cx);
20370    }
20371
20372    pub fn highlight_background<T: 'static>(
20373        &mut self,
20374        ranges: &[Range<Anchor>],
20375        color_fetcher: fn(&Theme) -> Hsla,
20376        cx: &mut Context<Self>,
20377    ) {
20378        self.background_highlights.insert(
20379            HighlightKey::Type(TypeId::of::<T>()),
20380            (color_fetcher, Arc::from(ranges)),
20381        );
20382        self.scrollbar_marker_state.dirty = true;
20383        cx.notify();
20384    }
20385
20386    pub fn highlight_background_key<T: 'static>(
20387        &mut self,
20388        key: usize,
20389        ranges: &[Range<Anchor>],
20390        color_fetcher: fn(&Theme) -> Hsla,
20391        cx: &mut Context<Self>,
20392    ) {
20393        self.background_highlights.insert(
20394            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20395            (color_fetcher, Arc::from(ranges)),
20396        );
20397        self.scrollbar_marker_state.dirty = true;
20398        cx.notify();
20399    }
20400
20401    pub fn clear_background_highlights<T: 'static>(
20402        &mut self,
20403        cx: &mut Context<Self>,
20404    ) -> Option<BackgroundHighlight> {
20405        let text_highlights = self
20406            .background_highlights
20407            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20408        if !text_highlights.1.is_empty() {
20409            self.scrollbar_marker_state.dirty = true;
20410            cx.notify();
20411        }
20412        Some(text_highlights)
20413    }
20414
20415    pub fn highlight_gutter<T: 'static>(
20416        &mut self,
20417        ranges: impl Into<Vec<Range<Anchor>>>,
20418        color_fetcher: fn(&App) -> Hsla,
20419        cx: &mut Context<Self>,
20420    ) {
20421        self.gutter_highlights
20422            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20423        cx.notify();
20424    }
20425
20426    pub fn clear_gutter_highlights<T: 'static>(
20427        &mut self,
20428        cx: &mut Context<Self>,
20429    ) -> Option<GutterHighlight> {
20430        cx.notify();
20431        self.gutter_highlights.remove(&TypeId::of::<T>())
20432    }
20433
20434    pub fn insert_gutter_highlight<T: 'static>(
20435        &mut self,
20436        range: Range<Anchor>,
20437        color_fetcher: fn(&App) -> Hsla,
20438        cx: &mut Context<Self>,
20439    ) {
20440        let snapshot = self.buffer().read(cx).snapshot(cx);
20441        let mut highlights = self
20442            .gutter_highlights
20443            .remove(&TypeId::of::<T>())
20444            .map(|(_, highlights)| highlights)
20445            .unwrap_or_default();
20446        let ix = highlights.binary_search_by(|highlight| {
20447            Ordering::Equal
20448                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20449                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20450        });
20451        if let Err(ix) = ix {
20452            highlights.insert(ix, range);
20453        }
20454        self.gutter_highlights
20455            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20456    }
20457
20458    pub fn remove_gutter_highlights<T: 'static>(
20459        &mut self,
20460        ranges_to_remove: Vec<Range<Anchor>>,
20461        cx: &mut Context<Self>,
20462    ) {
20463        let snapshot = self.buffer().read(cx).snapshot(cx);
20464        let Some((color_fetcher, mut gutter_highlights)) =
20465            self.gutter_highlights.remove(&TypeId::of::<T>())
20466        else {
20467            return;
20468        };
20469        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20470        gutter_highlights.retain(|highlight| {
20471            while let Some(range_to_remove) = ranges_to_remove.peek() {
20472                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20473                    Ordering::Less | Ordering::Equal => {
20474                        ranges_to_remove.next();
20475                    }
20476                    Ordering::Greater => {
20477                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20478                            Ordering::Less | Ordering::Equal => {
20479                                return false;
20480                            }
20481                            Ordering::Greater => break,
20482                        }
20483                    }
20484                }
20485            }
20486
20487            true
20488        });
20489        self.gutter_highlights
20490            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20491    }
20492
20493    #[cfg(feature = "test-support")]
20494    pub fn all_text_highlights(
20495        &self,
20496        window: &mut Window,
20497        cx: &mut Context<Self>,
20498    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20499        let snapshot = self.snapshot(window, cx);
20500        self.display_map.update(cx, |display_map, _| {
20501            display_map
20502                .all_text_highlights()
20503                .map(|highlight| {
20504                    let (style, ranges) = highlight.as_ref();
20505                    (
20506                        *style,
20507                        ranges
20508                            .iter()
20509                            .map(|range| range.clone().to_display_points(&snapshot))
20510                            .collect(),
20511                    )
20512                })
20513                .collect()
20514        })
20515    }
20516
20517    #[cfg(feature = "test-support")]
20518    pub fn all_text_background_highlights(
20519        &self,
20520        window: &mut Window,
20521        cx: &mut Context<Self>,
20522    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20523        let snapshot = self.snapshot(window, cx);
20524        let buffer = &snapshot.buffer_snapshot();
20525        let start = buffer.anchor_before(0);
20526        let end = buffer.anchor_after(buffer.len());
20527        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20528    }
20529
20530    #[cfg(any(test, feature = "test-support"))]
20531    pub fn sorted_background_highlights_in_range(
20532        &self,
20533        search_range: Range<Anchor>,
20534        display_snapshot: &DisplaySnapshot,
20535        theme: &Theme,
20536    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20537        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20538        res.sort_by(|a, b| {
20539            a.0.start
20540                .cmp(&b.0.start)
20541                .then_with(|| a.0.end.cmp(&b.0.end))
20542                .then_with(|| a.1.cmp(&b.1))
20543        });
20544        res
20545    }
20546
20547    #[cfg(feature = "test-support")]
20548    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20549        let snapshot = self.buffer().read(cx).snapshot(cx);
20550
20551        let highlights = self
20552            .background_highlights
20553            .get(&HighlightKey::Type(TypeId::of::<
20554                items::BufferSearchHighlights,
20555            >()));
20556
20557        if let Some((_color, ranges)) = highlights {
20558            ranges
20559                .iter()
20560                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20561                .collect_vec()
20562        } else {
20563            vec![]
20564        }
20565    }
20566
20567    fn document_highlights_for_position<'a>(
20568        &'a self,
20569        position: Anchor,
20570        buffer: &'a MultiBufferSnapshot,
20571    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20572        let read_highlights = self
20573            .background_highlights
20574            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20575            .map(|h| &h.1);
20576        let write_highlights = self
20577            .background_highlights
20578            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20579            .map(|h| &h.1);
20580        let left_position = position.bias_left(buffer);
20581        let right_position = position.bias_right(buffer);
20582        read_highlights
20583            .into_iter()
20584            .chain(write_highlights)
20585            .flat_map(move |ranges| {
20586                let start_ix = match ranges.binary_search_by(|probe| {
20587                    let cmp = probe.end.cmp(&left_position, buffer);
20588                    if cmp.is_ge() {
20589                        Ordering::Greater
20590                    } else {
20591                        Ordering::Less
20592                    }
20593                }) {
20594                    Ok(i) | Err(i) => i,
20595                };
20596
20597                ranges[start_ix..]
20598                    .iter()
20599                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20600            })
20601    }
20602
20603    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20604        self.background_highlights
20605            .get(&HighlightKey::Type(TypeId::of::<T>()))
20606            .is_some_and(|(_, highlights)| !highlights.is_empty())
20607    }
20608
20609    /// Returns all background highlights for a given range.
20610    ///
20611    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20612    pub fn background_highlights_in_range(
20613        &self,
20614        search_range: Range<Anchor>,
20615        display_snapshot: &DisplaySnapshot,
20616        theme: &Theme,
20617    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20618        let mut results = Vec::new();
20619        for (color_fetcher, ranges) in self.background_highlights.values() {
20620            let color = color_fetcher(theme);
20621            let start_ix = match ranges.binary_search_by(|probe| {
20622                let cmp = probe
20623                    .end
20624                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20625                if cmp.is_gt() {
20626                    Ordering::Greater
20627                } else {
20628                    Ordering::Less
20629                }
20630            }) {
20631                Ok(i) | Err(i) => i,
20632            };
20633            for range in &ranges[start_ix..] {
20634                if range
20635                    .start
20636                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20637                    .is_ge()
20638                {
20639                    break;
20640                }
20641
20642                let start = range.start.to_display_point(display_snapshot);
20643                let end = range.end.to_display_point(display_snapshot);
20644                results.push((start..end, color))
20645            }
20646        }
20647        results
20648    }
20649
20650    pub fn gutter_highlights_in_range(
20651        &self,
20652        search_range: Range<Anchor>,
20653        display_snapshot: &DisplaySnapshot,
20654        cx: &App,
20655    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20656        let mut results = Vec::new();
20657        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20658            let color = color_fetcher(cx);
20659            let start_ix = match ranges.binary_search_by(|probe| {
20660                let cmp = probe
20661                    .end
20662                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20663                if cmp.is_gt() {
20664                    Ordering::Greater
20665                } else {
20666                    Ordering::Less
20667                }
20668            }) {
20669                Ok(i) | Err(i) => i,
20670            };
20671            for range in &ranges[start_ix..] {
20672                if range
20673                    .start
20674                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20675                    .is_ge()
20676                {
20677                    break;
20678                }
20679
20680                let start = range.start.to_display_point(display_snapshot);
20681                let end = range.end.to_display_point(display_snapshot);
20682                results.push((start..end, color))
20683            }
20684        }
20685        results
20686    }
20687
20688    /// Get the text ranges corresponding to the redaction query
20689    pub fn redacted_ranges(
20690        &self,
20691        search_range: Range<Anchor>,
20692        display_snapshot: &DisplaySnapshot,
20693        cx: &App,
20694    ) -> Vec<Range<DisplayPoint>> {
20695        display_snapshot
20696            .buffer_snapshot()
20697            .redacted_ranges(search_range, |file| {
20698                if let Some(file) = file {
20699                    file.is_private()
20700                        && EditorSettings::get(
20701                            Some(SettingsLocation {
20702                                worktree_id: file.worktree_id(cx),
20703                                path: file.path().as_ref(),
20704                            }),
20705                            cx,
20706                        )
20707                        .redact_private_values
20708                } else {
20709                    false
20710                }
20711            })
20712            .map(|range| {
20713                range.start.to_display_point(display_snapshot)
20714                    ..range.end.to_display_point(display_snapshot)
20715            })
20716            .collect()
20717    }
20718
20719    pub fn highlight_text_key<T: 'static>(
20720        &mut self,
20721        key: usize,
20722        ranges: Vec<Range<Anchor>>,
20723        style: HighlightStyle,
20724        cx: &mut Context<Self>,
20725    ) {
20726        self.display_map.update(cx, |map, _| {
20727            map.highlight_text(
20728                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20729                ranges,
20730                style,
20731            );
20732        });
20733        cx.notify();
20734    }
20735
20736    pub fn highlight_text<T: 'static>(
20737        &mut self,
20738        ranges: Vec<Range<Anchor>>,
20739        style: HighlightStyle,
20740        cx: &mut Context<Self>,
20741    ) {
20742        self.display_map.update(cx, |map, _| {
20743            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20744        });
20745        cx.notify();
20746    }
20747
20748    pub fn text_highlights<'a, T: 'static>(
20749        &'a self,
20750        cx: &'a App,
20751    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20752        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20753    }
20754
20755    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20756        let cleared = self
20757            .display_map
20758            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20759        if cleared {
20760            cx.notify();
20761        }
20762    }
20763
20764    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20765        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20766            && self.focus_handle.is_focused(window)
20767    }
20768
20769    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20770        self.show_cursor_when_unfocused = is_enabled;
20771        cx.notify();
20772    }
20773
20774    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20775        cx.notify();
20776    }
20777
20778    fn on_debug_session_event(
20779        &mut self,
20780        _session: Entity<Session>,
20781        event: &SessionEvent,
20782        cx: &mut Context<Self>,
20783    ) {
20784        if let SessionEvent::InvalidateInlineValue = event {
20785            self.refresh_inline_values(cx);
20786        }
20787    }
20788
20789    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20790        let Some(project) = self.project.clone() else {
20791            return;
20792        };
20793
20794        if !self.inline_value_cache.enabled {
20795            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20796            self.splice_inlays(&inlays, Vec::new(), cx);
20797            return;
20798        }
20799
20800        let current_execution_position = self
20801            .highlighted_rows
20802            .get(&TypeId::of::<ActiveDebugLine>())
20803            .and_then(|lines| lines.last().map(|line| line.range.end));
20804
20805        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20806            let inline_values = editor
20807                .update(cx, |editor, cx| {
20808                    let Some(current_execution_position) = current_execution_position else {
20809                        return Some(Task::ready(Ok(Vec::new())));
20810                    };
20811
20812                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20813                        let snapshot = buffer.snapshot(cx);
20814
20815                        let excerpt = snapshot.excerpt_containing(
20816                            current_execution_position..current_execution_position,
20817                        )?;
20818
20819                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20820                    })?;
20821
20822                    let range =
20823                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20824
20825                    project.inline_values(buffer, range, cx)
20826                })
20827                .ok()
20828                .flatten()?
20829                .await
20830                .context("refreshing debugger inlays")
20831                .log_err()?;
20832
20833            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20834
20835            for (buffer_id, inline_value) in inline_values
20836                .into_iter()
20837                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20838            {
20839                buffer_inline_values
20840                    .entry(buffer_id)
20841                    .or_default()
20842                    .push(inline_value);
20843            }
20844
20845            editor
20846                .update(cx, |editor, cx| {
20847                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20848                    let mut new_inlays = Vec::default();
20849
20850                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20851                        let buffer_id = buffer_snapshot.remote_id();
20852                        buffer_inline_values
20853                            .get(&buffer_id)
20854                            .into_iter()
20855                            .flatten()
20856                            .for_each(|hint| {
20857                                let inlay = Inlay::debugger(
20858                                    post_inc(&mut editor.next_inlay_id),
20859                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20860                                    hint.text(),
20861                                );
20862                                if !inlay.text().chars().contains(&'\n') {
20863                                    new_inlays.push(inlay);
20864                                }
20865                            });
20866                    }
20867
20868                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20869                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20870
20871                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20872                })
20873                .ok()?;
20874            Some(())
20875        });
20876    }
20877
20878    fn on_buffer_event(
20879        &mut self,
20880        multibuffer: &Entity<MultiBuffer>,
20881        event: &multi_buffer::Event,
20882        window: &mut Window,
20883        cx: &mut Context<Self>,
20884    ) {
20885        match event {
20886            multi_buffer::Event::Edited { edited_buffer } => {
20887                self.scrollbar_marker_state.dirty = true;
20888                self.active_indent_guides_state.dirty = true;
20889                self.refresh_active_diagnostics(cx);
20890                self.refresh_code_actions(window, cx);
20891                self.refresh_selected_text_highlights(true, window, cx);
20892                self.refresh_single_line_folds(window, cx);
20893                self.refresh_matching_bracket_highlights(window, cx);
20894                if self.has_active_edit_prediction() {
20895                    self.update_visible_edit_prediction(window, cx);
20896                }
20897
20898                if let Some(buffer) = edited_buffer {
20899                    if buffer.read(cx).file().is_none() {
20900                        cx.emit(EditorEvent::TitleChanged);
20901                    }
20902
20903                    if self.project.is_some() {
20904                        let buffer_id = buffer.read(cx).remote_id();
20905                        self.register_buffer(buffer_id, cx);
20906                        self.update_lsp_data(Some(buffer_id), window, cx);
20907                        self.refresh_inlay_hints(
20908                            InlayHintRefreshReason::BufferEdited(buffer_id),
20909                            cx,
20910                        );
20911                    }
20912                }
20913
20914                cx.emit(EditorEvent::BufferEdited);
20915                cx.emit(SearchEvent::MatchesInvalidated);
20916
20917                let Some(project) = &self.project else { return };
20918                let (telemetry, is_via_ssh) = {
20919                    let project = project.read(cx);
20920                    let telemetry = project.client().telemetry().clone();
20921                    let is_via_ssh = project.is_via_remote_server();
20922                    (telemetry, is_via_ssh)
20923                };
20924                telemetry.log_edit_event("editor", is_via_ssh);
20925            }
20926            multi_buffer::Event::ExcerptsAdded {
20927                buffer,
20928                predecessor,
20929                excerpts,
20930            } => {
20931                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20932                let buffer_id = buffer.read(cx).remote_id();
20933                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20934                    && let Some(project) = &self.project
20935                {
20936                    update_uncommitted_diff_for_buffer(
20937                        cx.entity(),
20938                        project,
20939                        [buffer.clone()],
20940                        self.buffer.clone(),
20941                        cx,
20942                    )
20943                    .detach();
20944                }
20945                self.update_lsp_data(Some(buffer_id), window, cx);
20946                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20947                cx.emit(EditorEvent::ExcerptsAdded {
20948                    buffer: buffer.clone(),
20949                    predecessor: *predecessor,
20950                    excerpts: excerpts.clone(),
20951                });
20952            }
20953            multi_buffer::Event::ExcerptsRemoved {
20954                ids,
20955                removed_buffer_ids,
20956            } => {
20957                if let Some(inlay_hints) = &mut self.inlay_hints {
20958                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
20959                }
20960                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20961                for buffer_id in removed_buffer_ids {
20962                    self.registered_buffers.remove(buffer_id);
20963                }
20964                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20965                cx.emit(EditorEvent::ExcerptsRemoved {
20966                    ids: ids.clone(),
20967                    removed_buffer_ids: removed_buffer_ids.clone(),
20968                });
20969            }
20970            multi_buffer::Event::ExcerptsEdited {
20971                excerpt_ids,
20972                buffer_ids,
20973            } => {
20974                self.display_map.update(cx, |map, cx| {
20975                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20976                });
20977                cx.emit(EditorEvent::ExcerptsEdited {
20978                    ids: excerpt_ids.clone(),
20979                });
20980            }
20981            multi_buffer::Event::ExcerptsExpanded { ids } => {
20982                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20983                self.refresh_document_highlights(cx);
20984                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20985            }
20986            multi_buffer::Event::Reparsed(buffer_id) => {
20987                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20988                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20989
20990                cx.emit(EditorEvent::Reparsed(*buffer_id));
20991            }
20992            multi_buffer::Event::DiffHunksToggled => {
20993                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20994            }
20995            multi_buffer::Event::LanguageChanged(buffer_id) => {
20996                self.registered_buffers.remove(&buffer_id);
20997                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20998                cx.emit(EditorEvent::Reparsed(*buffer_id));
20999                cx.notify();
21000            }
21001            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21002            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21003            multi_buffer::Event::FileHandleChanged
21004            | multi_buffer::Event::Reloaded
21005            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21006            multi_buffer::Event::DiagnosticsUpdated => {
21007                self.update_diagnostics_state(window, cx);
21008            }
21009            _ => {}
21010        };
21011    }
21012
21013    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21014        if !self.diagnostics_enabled() {
21015            return;
21016        }
21017        self.refresh_active_diagnostics(cx);
21018        self.refresh_inline_diagnostics(true, window, cx);
21019        self.scrollbar_marker_state.dirty = true;
21020        cx.notify();
21021    }
21022
21023    pub fn start_temporary_diff_override(&mut self) {
21024        self.load_diff_task.take();
21025        self.temporary_diff_override = true;
21026    }
21027
21028    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21029        self.temporary_diff_override = false;
21030        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21031        self.buffer.update(cx, |buffer, cx| {
21032            buffer.set_all_diff_hunks_collapsed(cx);
21033        });
21034
21035        if let Some(project) = self.project.clone() {
21036            self.load_diff_task = Some(
21037                update_uncommitted_diff_for_buffer(
21038                    cx.entity(),
21039                    &project,
21040                    self.buffer.read(cx).all_buffers(),
21041                    self.buffer.clone(),
21042                    cx,
21043                )
21044                .shared(),
21045            );
21046        }
21047    }
21048
21049    fn on_display_map_changed(
21050        &mut self,
21051        _: Entity<DisplayMap>,
21052        _: &mut Window,
21053        cx: &mut Context<Self>,
21054    ) {
21055        cx.notify();
21056    }
21057
21058    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21059        if self.diagnostics_enabled() {
21060            let new_severity = EditorSettings::get_global(cx)
21061                .diagnostics_max_severity
21062                .unwrap_or(DiagnosticSeverity::Hint);
21063            self.set_max_diagnostics_severity(new_severity, cx);
21064        }
21065        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21066        self.update_edit_prediction_settings(cx);
21067        self.refresh_edit_prediction(true, false, window, cx);
21068        self.refresh_inline_values(cx);
21069        self.refresh_inlay_hints(
21070            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21071                self.selections.newest_anchor().head(),
21072                &self.buffer.read(cx).snapshot(cx),
21073                cx,
21074            )),
21075            cx,
21076        );
21077
21078        let old_cursor_shape = self.cursor_shape;
21079        let old_show_breadcrumbs = self.show_breadcrumbs;
21080
21081        {
21082            let editor_settings = EditorSettings::get_global(cx);
21083            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21084            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21085            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21086            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21087        }
21088
21089        if old_cursor_shape != self.cursor_shape {
21090            cx.emit(EditorEvent::CursorShapeChanged);
21091        }
21092
21093        if old_show_breadcrumbs != self.show_breadcrumbs {
21094            cx.emit(EditorEvent::BreadcrumbsChanged);
21095        }
21096
21097        let project_settings = ProjectSettings::get_global(cx);
21098        self.serialize_dirty_buffers =
21099            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21100
21101        if self.mode.is_full() {
21102            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21103            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21104            if self.show_inline_diagnostics != show_inline_diagnostics {
21105                self.show_inline_diagnostics = show_inline_diagnostics;
21106                self.refresh_inline_diagnostics(false, window, cx);
21107            }
21108
21109            if self.git_blame_inline_enabled != inline_blame_enabled {
21110                self.toggle_git_blame_inline_internal(false, window, cx);
21111            }
21112
21113            let minimap_settings = EditorSettings::get_global(cx).minimap;
21114            if self.minimap_visibility != MinimapVisibility::Disabled {
21115                if self.minimap_visibility.settings_visibility()
21116                    != minimap_settings.minimap_enabled()
21117                {
21118                    self.set_minimap_visibility(
21119                        MinimapVisibility::for_mode(self.mode(), cx),
21120                        window,
21121                        cx,
21122                    );
21123                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21124                    minimap_entity.update(cx, |minimap_editor, cx| {
21125                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21126                    })
21127                }
21128            }
21129        }
21130
21131        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21132            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21133        }) {
21134            if !inlay_splice.is_empty() {
21135                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21136            }
21137            self.refresh_colors_for_visible_range(None, window, cx);
21138        }
21139
21140        cx.notify();
21141    }
21142
21143    pub fn set_searchable(&mut self, searchable: bool) {
21144        self.searchable = searchable;
21145    }
21146
21147    pub fn searchable(&self) -> bool {
21148        self.searchable
21149    }
21150
21151    pub fn open_excerpts_in_split(
21152        &mut self,
21153        _: &OpenExcerptsSplit,
21154        window: &mut Window,
21155        cx: &mut Context<Self>,
21156    ) {
21157        self.open_excerpts_common(None, true, window, cx)
21158    }
21159
21160    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21161        self.open_excerpts_common(None, false, window, cx)
21162    }
21163
21164    fn open_excerpts_common(
21165        &mut self,
21166        jump_data: Option<JumpData>,
21167        split: bool,
21168        window: &mut Window,
21169        cx: &mut Context<Self>,
21170    ) {
21171        let Some(workspace) = self.workspace() else {
21172            cx.propagate();
21173            return;
21174        };
21175
21176        if self.buffer.read(cx).is_singleton() {
21177            cx.propagate();
21178            return;
21179        }
21180
21181        let mut new_selections_by_buffer = HashMap::default();
21182        match &jump_data {
21183            Some(JumpData::MultiBufferPoint {
21184                excerpt_id,
21185                position,
21186                anchor,
21187                line_offset_from_top,
21188            }) => {
21189                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21190                if let Some(buffer) = multi_buffer_snapshot
21191                    .buffer_id_for_excerpt(*excerpt_id)
21192                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21193                {
21194                    let buffer_snapshot = buffer.read(cx).snapshot();
21195                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21196                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21197                    } else {
21198                        buffer_snapshot.clip_point(*position, Bias::Left)
21199                    };
21200                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21201                    new_selections_by_buffer.insert(
21202                        buffer,
21203                        (
21204                            vec![jump_to_offset..jump_to_offset],
21205                            Some(*line_offset_from_top),
21206                        ),
21207                    );
21208                }
21209            }
21210            Some(JumpData::MultiBufferRow {
21211                row,
21212                line_offset_from_top,
21213            }) => {
21214                let point = MultiBufferPoint::new(row.0, 0);
21215                if let Some((buffer, buffer_point, _)) =
21216                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21217                {
21218                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21219                    new_selections_by_buffer
21220                        .entry(buffer)
21221                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21222                        .0
21223                        .push(buffer_offset..buffer_offset)
21224                }
21225            }
21226            None => {
21227                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21228                let multi_buffer = self.buffer.read(cx);
21229                for selection in selections {
21230                    for (snapshot, range, _, anchor) in multi_buffer
21231                        .snapshot(cx)
21232                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21233                    {
21234                        if let Some(anchor) = anchor {
21235                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21236                            else {
21237                                continue;
21238                            };
21239                            let offset = text::ToOffset::to_offset(
21240                                &anchor.text_anchor,
21241                                &buffer_handle.read(cx).snapshot(),
21242                            );
21243                            let range = offset..offset;
21244                            new_selections_by_buffer
21245                                .entry(buffer_handle)
21246                                .or_insert((Vec::new(), None))
21247                                .0
21248                                .push(range)
21249                        } else {
21250                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21251                            else {
21252                                continue;
21253                            };
21254                            new_selections_by_buffer
21255                                .entry(buffer_handle)
21256                                .or_insert((Vec::new(), None))
21257                                .0
21258                                .push(range)
21259                        }
21260                    }
21261                }
21262            }
21263        }
21264
21265        new_selections_by_buffer
21266            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21267
21268        if new_selections_by_buffer.is_empty() {
21269            return;
21270        }
21271
21272        // We defer the pane interaction because we ourselves are a workspace item
21273        // and activating a new item causes the pane to call a method on us reentrantly,
21274        // which panics if we're on the stack.
21275        window.defer(cx, move |window, cx| {
21276            workspace.update(cx, |workspace, cx| {
21277                let pane = if split {
21278                    workspace.adjacent_pane(window, cx)
21279                } else {
21280                    workspace.active_pane().clone()
21281                };
21282
21283                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21284                    let editor = buffer
21285                        .read(cx)
21286                        .file()
21287                        .is_none()
21288                        .then(|| {
21289                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21290                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21291                            // Instead, we try to activate the existing editor in the pane first.
21292                            let (editor, pane_item_index) =
21293                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21294                                    let editor = item.downcast::<Editor>()?;
21295                                    let singleton_buffer =
21296                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21297                                    if singleton_buffer == buffer {
21298                                        Some((editor, i))
21299                                    } else {
21300                                        None
21301                                    }
21302                                })?;
21303                            pane.update(cx, |pane, cx| {
21304                                pane.activate_item(pane_item_index, true, true, window, cx)
21305                            });
21306                            Some(editor)
21307                        })
21308                        .flatten()
21309                        .unwrap_or_else(|| {
21310                            workspace.open_project_item::<Self>(
21311                                pane.clone(),
21312                                buffer,
21313                                true,
21314                                true,
21315                                window,
21316                                cx,
21317                            )
21318                        });
21319
21320                    editor.update(cx, |editor, cx| {
21321                        let autoscroll = match scroll_offset {
21322                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21323                            None => Autoscroll::newest(),
21324                        };
21325                        let nav_history = editor.nav_history.take();
21326                        editor.change_selections(
21327                            SelectionEffects::scroll(autoscroll),
21328                            window,
21329                            cx,
21330                            |s| {
21331                                s.select_ranges(ranges);
21332                            },
21333                        );
21334                        editor.nav_history = nav_history;
21335                    });
21336                }
21337            })
21338        });
21339    }
21340
21341    // For now, don't allow opening excerpts in buffers that aren't backed by
21342    // regular project files.
21343    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21344        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21345    }
21346
21347    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21348        let snapshot = self.buffer.read(cx).read(cx);
21349        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21350        Some(
21351            ranges
21352                .iter()
21353                .map(move |range| {
21354                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21355                })
21356                .collect(),
21357        )
21358    }
21359
21360    fn selection_replacement_ranges(
21361        &self,
21362        range: Range<OffsetUtf16>,
21363        cx: &mut App,
21364    ) -> Vec<Range<OffsetUtf16>> {
21365        let selections = self
21366            .selections
21367            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21368        let newest_selection = selections
21369            .iter()
21370            .max_by_key(|selection| selection.id)
21371            .unwrap();
21372        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21373        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21374        let snapshot = self.buffer.read(cx).read(cx);
21375        selections
21376            .into_iter()
21377            .map(|mut selection| {
21378                selection.start.0 =
21379                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21380                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21381                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21382                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21383            })
21384            .collect()
21385    }
21386
21387    fn report_editor_event(
21388        &self,
21389        reported_event: ReportEditorEvent,
21390        file_extension: Option<String>,
21391        cx: &App,
21392    ) {
21393        if cfg!(any(test, feature = "test-support")) {
21394            return;
21395        }
21396
21397        let Some(project) = &self.project else { return };
21398
21399        // If None, we are in a file without an extension
21400        let file = self
21401            .buffer
21402            .read(cx)
21403            .as_singleton()
21404            .and_then(|b| b.read(cx).file());
21405        let file_extension = file_extension.or(file
21406            .as_ref()
21407            .and_then(|file| Path::new(file.file_name(cx)).extension())
21408            .and_then(|e| e.to_str())
21409            .map(|a| a.to_string()));
21410
21411        let vim_mode = vim_enabled(cx);
21412
21413        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21414        let copilot_enabled = edit_predictions_provider
21415            == language::language_settings::EditPredictionProvider::Copilot;
21416        let copilot_enabled_for_language = self
21417            .buffer
21418            .read(cx)
21419            .language_settings(cx)
21420            .show_edit_predictions;
21421
21422        let project = project.read(cx);
21423        let event_type = reported_event.event_type();
21424
21425        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21426            telemetry::event!(
21427                event_type,
21428                type = if auto_saved {"autosave"} else {"manual"},
21429                file_extension,
21430                vim_mode,
21431                copilot_enabled,
21432                copilot_enabled_for_language,
21433                edit_predictions_provider,
21434                is_via_ssh = project.is_via_remote_server(),
21435            );
21436        } else {
21437            telemetry::event!(
21438                event_type,
21439                file_extension,
21440                vim_mode,
21441                copilot_enabled,
21442                copilot_enabled_for_language,
21443                edit_predictions_provider,
21444                is_via_ssh = project.is_via_remote_server(),
21445            );
21446        };
21447    }
21448
21449    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21450    /// with each line being an array of {text, highlight} objects.
21451    fn copy_highlight_json(
21452        &mut self,
21453        _: &CopyHighlightJson,
21454        window: &mut Window,
21455        cx: &mut Context<Self>,
21456    ) {
21457        #[derive(Serialize)]
21458        struct Chunk<'a> {
21459            text: String,
21460            highlight: Option<&'a str>,
21461        }
21462
21463        let snapshot = self.buffer.read(cx).snapshot(cx);
21464        let range = self
21465            .selected_text_range(false, window, cx)
21466            .and_then(|selection| {
21467                if selection.range.is_empty() {
21468                    None
21469                } else {
21470                    Some(
21471                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21472                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21473                    )
21474                }
21475            })
21476            .unwrap_or_else(|| 0..snapshot.len());
21477
21478        let chunks = snapshot.chunks(range, true);
21479        let mut lines = Vec::new();
21480        let mut line: VecDeque<Chunk> = VecDeque::new();
21481
21482        let Some(style) = self.style.as_ref() else {
21483            return;
21484        };
21485
21486        for chunk in chunks {
21487            let highlight = chunk
21488                .syntax_highlight_id
21489                .and_then(|id| id.name(&style.syntax));
21490            let mut chunk_lines = chunk.text.split('\n').peekable();
21491            while let Some(text) = chunk_lines.next() {
21492                let mut merged_with_last_token = false;
21493                if let Some(last_token) = line.back_mut()
21494                    && last_token.highlight == highlight
21495                {
21496                    last_token.text.push_str(text);
21497                    merged_with_last_token = true;
21498                }
21499
21500                if !merged_with_last_token {
21501                    line.push_back(Chunk {
21502                        text: text.into(),
21503                        highlight,
21504                    });
21505                }
21506
21507                if chunk_lines.peek().is_some() {
21508                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21509                        line.pop_front();
21510                    }
21511                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21512                        line.pop_back();
21513                    }
21514
21515                    lines.push(mem::take(&mut line));
21516                }
21517            }
21518        }
21519
21520        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21521            return;
21522        };
21523        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21524    }
21525
21526    pub fn open_context_menu(
21527        &mut self,
21528        _: &OpenContextMenu,
21529        window: &mut Window,
21530        cx: &mut Context<Self>,
21531    ) {
21532        self.request_autoscroll(Autoscroll::newest(), cx);
21533        let position = self
21534            .selections
21535            .newest_display(&self.display_snapshot(cx))
21536            .start;
21537        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21538    }
21539
21540    pub fn replay_insert_event(
21541        &mut self,
21542        text: &str,
21543        relative_utf16_range: Option<Range<isize>>,
21544        window: &mut Window,
21545        cx: &mut Context<Self>,
21546    ) {
21547        if !self.input_enabled {
21548            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21549            return;
21550        }
21551        if let Some(relative_utf16_range) = relative_utf16_range {
21552            let selections = self
21553                .selections
21554                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21555            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21556                let new_ranges = selections.into_iter().map(|range| {
21557                    let start = OffsetUtf16(
21558                        range
21559                            .head()
21560                            .0
21561                            .saturating_add_signed(relative_utf16_range.start),
21562                    );
21563                    let end = OffsetUtf16(
21564                        range
21565                            .head()
21566                            .0
21567                            .saturating_add_signed(relative_utf16_range.end),
21568                    );
21569                    start..end
21570                });
21571                s.select_ranges(new_ranges);
21572            });
21573        }
21574
21575        self.handle_input(text, window, cx);
21576    }
21577
21578    pub fn is_focused(&self, window: &Window) -> bool {
21579        self.focus_handle.is_focused(window)
21580    }
21581
21582    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21583        cx.emit(EditorEvent::Focused);
21584
21585        if let Some(descendant) = self
21586            .last_focused_descendant
21587            .take()
21588            .and_then(|descendant| descendant.upgrade())
21589        {
21590            window.focus(&descendant);
21591        } else {
21592            if let Some(blame) = self.blame.as_ref() {
21593                blame.update(cx, GitBlame::focus)
21594            }
21595
21596            self.blink_manager.update(cx, BlinkManager::enable);
21597            self.show_cursor_names(window, cx);
21598            self.buffer.update(cx, |buffer, cx| {
21599                buffer.finalize_last_transaction(cx);
21600                if self.leader_id.is_none() {
21601                    buffer.set_active_selections(
21602                        &self.selections.disjoint_anchors_arc(),
21603                        self.selections.line_mode(),
21604                        self.cursor_shape,
21605                        cx,
21606                    );
21607                }
21608            });
21609        }
21610    }
21611
21612    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21613        cx.emit(EditorEvent::FocusedIn)
21614    }
21615
21616    fn handle_focus_out(
21617        &mut self,
21618        event: FocusOutEvent,
21619        _window: &mut Window,
21620        cx: &mut Context<Self>,
21621    ) {
21622        if event.blurred != self.focus_handle {
21623            self.last_focused_descendant = Some(event.blurred);
21624        }
21625        self.selection_drag_state = SelectionDragState::None;
21626        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21627    }
21628
21629    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21630        self.blink_manager.update(cx, BlinkManager::disable);
21631        self.buffer
21632            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21633
21634        if let Some(blame) = self.blame.as_ref() {
21635            blame.update(cx, GitBlame::blur)
21636        }
21637        if !self.hover_state.focused(window, cx) {
21638            hide_hover(self, cx);
21639        }
21640        if !self
21641            .context_menu
21642            .borrow()
21643            .as_ref()
21644            .is_some_and(|context_menu| context_menu.focused(window, cx))
21645        {
21646            self.hide_context_menu(window, cx);
21647        }
21648        self.take_active_edit_prediction(cx);
21649        cx.emit(EditorEvent::Blurred);
21650        cx.notify();
21651    }
21652
21653    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21654        let mut pending: String = window
21655            .pending_input_keystrokes()
21656            .into_iter()
21657            .flatten()
21658            .filter_map(|keystroke| {
21659                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21660                    keystroke.key_char.clone()
21661                } else {
21662                    None
21663                }
21664            })
21665            .collect();
21666
21667        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21668            pending = "".to_string();
21669        }
21670
21671        let existing_pending = self
21672            .text_highlights::<PendingInput>(cx)
21673            .map(|(_, ranges)| ranges.to_vec());
21674        if existing_pending.is_none() && pending.is_empty() {
21675            return;
21676        }
21677        let transaction =
21678            self.transact(window, cx, |this, window, cx| {
21679                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21680                let edits = selections
21681                    .iter()
21682                    .map(|selection| (selection.end..selection.end, pending.clone()));
21683                this.edit(edits, cx);
21684                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21685                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21686                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21687                    }));
21688                });
21689                if let Some(existing_ranges) = existing_pending {
21690                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21691                    this.edit(edits, cx);
21692                }
21693            });
21694
21695        let snapshot = self.snapshot(window, cx);
21696        let ranges = self
21697            .selections
21698            .all::<usize>(&snapshot.display_snapshot)
21699            .into_iter()
21700            .map(|selection| {
21701                snapshot.buffer_snapshot().anchor_after(selection.end)
21702                    ..snapshot
21703                        .buffer_snapshot()
21704                        .anchor_before(selection.end + pending.len())
21705            })
21706            .collect();
21707
21708        if pending.is_empty() {
21709            self.clear_highlights::<PendingInput>(cx);
21710        } else {
21711            self.highlight_text::<PendingInput>(
21712                ranges,
21713                HighlightStyle {
21714                    underline: Some(UnderlineStyle {
21715                        thickness: px(1.),
21716                        color: None,
21717                        wavy: false,
21718                    }),
21719                    ..Default::default()
21720                },
21721                cx,
21722            );
21723        }
21724
21725        self.ime_transaction = self.ime_transaction.or(transaction);
21726        if let Some(transaction) = self.ime_transaction {
21727            self.buffer.update(cx, |buffer, cx| {
21728                buffer.group_until_transaction(transaction, cx);
21729            });
21730        }
21731
21732        if self.text_highlights::<PendingInput>(cx).is_none() {
21733            self.ime_transaction.take();
21734        }
21735    }
21736
21737    pub fn register_action_renderer(
21738        &mut self,
21739        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21740    ) -> Subscription {
21741        let id = self.next_editor_action_id.post_inc();
21742        self.editor_actions
21743            .borrow_mut()
21744            .insert(id, Box::new(listener));
21745
21746        let editor_actions = self.editor_actions.clone();
21747        Subscription::new(move || {
21748            editor_actions.borrow_mut().remove(&id);
21749        })
21750    }
21751
21752    pub fn register_action<A: Action>(
21753        &mut self,
21754        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21755    ) -> Subscription {
21756        let id = self.next_editor_action_id.post_inc();
21757        let listener = Arc::new(listener);
21758        self.editor_actions.borrow_mut().insert(
21759            id,
21760            Box::new(move |_, window, _| {
21761                let listener = listener.clone();
21762                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21763                    let action = action.downcast_ref().unwrap();
21764                    if phase == DispatchPhase::Bubble {
21765                        listener(action, window, cx)
21766                    }
21767                })
21768            }),
21769        );
21770
21771        let editor_actions = self.editor_actions.clone();
21772        Subscription::new(move || {
21773            editor_actions.borrow_mut().remove(&id);
21774        })
21775    }
21776
21777    pub fn file_header_size(&self) -> u32 {
21778        FILE_HEADER_HEIGHT
21779    }
21780
21781    pub fn restore(
21782        &mut self,
21783        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21784        window: &mut Window,
21785        cx: &mut Context<Self>,
21786    ) {
21787        let workspace = self.workspace();
21788        let project = self.project();
21789        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21790            let mut tasks = Vec::new();
21791            for (buffer_id, changes) in revert_changes {
21792                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21793                    buffer.update(cx, |buffer, cx| {
21794                        buffer.edit(
21795                            changes
21796                                .into_iter()
21797                                .map(|(range, text)| (range, text.to_string())),
21798                            None,
21799                            cx,
21800                        );
21801                    });
21802
21803                    if let Some(project) =
21804                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21805                    {
21806                        project.update(cx, |project, cx| {
21807                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21808                        })
21809                    }
21810                }
21811            }
21812            tasks
21813        });
21814        cx.spawn_in(window, async move |_, cx| {
21815            for (buffer, task) in save_tasks {
21816                let result = task.await;
21817                if result.is_err() {
21818                    let Some(path) = buffer
21819                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21820                        .ok()
21821                    else {
21822                        continue;
21823                    };
21824                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21825                        let Some(task) = cx
21826                            .update_window_entity(workspace, |workspace, window, cx| {
21827                                workspace
21828                                    .open_path_preview(path, None, false, false, false, window, cx)
21829                            })
21830                            .ok()
21831                        else {
21832                            continue;
21833                        };
21834                        task.await.log_err();
21835                    }
21836                }
21837            }
21838        })
21839        .detach();
21840        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21841            selections.refresh()
21842        });
21843    }
21844
21845    pub fn to_pixel_point(
21846        &self,
21847        source: multi_buffer::Anchor,
21848        editor_snapshot: &EditorSnapshot,
21849        window: &mut Window,
21850    ) -> Option<gpui::Point<Pixels>> {
21851        let source_point = source.to_display_point(editor_snapshot);
21852        self.display_to_pixel_point(source_point, editor_snapshot, window)
21853    }
21854
21855    pub fn display_to_pixel_point(
21856        &self,
21857        source: DisplayPoint,
21858        editor_snapshot: &EditorSnapshot,
21859        window: &mut Window,
21860    ) -> Option<gpui::Point<Pixels>> {
21861        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21862        let text_layout_details = self.text_layout_details(window);
21863        let scroll_top = text_layout_details
21864            .scroll_anchor
21865            .scroll_position(editor_snapshot)
21866            .y;
21867
21868        if source.row().as_f64() < scroll_top.floor() {
21869            return None;
21870        }
21871        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21872        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21873        Some(gpui::Point::new(source_x, source_y))
21874    }
21875
21876    pub fn has_visible_completions_menu(&self) -> bool {
21877        !self.edit_prediction_preview_is_active()
21878            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21879                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21880            })
21881    }
21882
21883    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21884        if self.mode.is_minimap() {
21885            return;
21886        }
21887        self.addons
21888            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21889    }
21890
21891    pub fn unregister_addon<T: Addon>(&mut self) {
21892        self.addons.remove(&std::any::TypeId::of::<T>());
21893    }
21894
21895    pub fn addon<T: Addon>(&self) -> Option<&T> {
21896        let type_id = std::any::TypeId::of::<T>();
21897        self.addons
21898            .get(&type_id)
21899            .and_then(|item| item.to_any().downcast_ref::<T>())
21900    }
21901
21902    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21903        let type_id = std::any::TypeId::of::<T>();
21904        self.addons
21905            .get_mut(&type_id)
21906            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21907    }
21908
21909    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21910        let text_layout_details = self.text_layout_details(window);
21911        let style = &text_layout_details.editor_style;
21912        let font_id = window.text_system().resolve_font(&style.text.font());
21913        let font_size = style.text.font_size.to_pixels(window.rem_size());
21914        let line_height = style.text.line_height_in_pixels(window.rem_size());
21915        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21916        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21917
21918        CharacterDimensions {
21919            em_width,
21920            em_advance,
21921            line_height,
21922        }
21923    }
21924
21925    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21926        self.load_diff_task.clone()
21927    }
21928
21929    fn read_metadata_from_db(
21930        &mut self,
21931        item_id: u64,
21932        workspace_id: WorkspaceId,
21933        window: &mut Window,
21934        cx: &mut Context<Editor>,
21935    ) {
21936        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21937            && !self.mode.is_minimap()
21938            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21939        {
21940            let buffer_snapshot = OnceCell::new();
21941
21942            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21943                && !folds.is_empty()
21944            {
21945                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21946                self.fold_ranges(
21947                    folds
21948                        .into_iter()
21949                        .map(|(start, end)| {
21950                            snapshot.clip_offset(start, Bias::Left)
21951                                ..snapshot.clip_offset(end, Bias::Right)
21952                        })
21953                        .collect(),
21954                    false,
21955                    window,
21956                    cx,
21957                );
21958            }
21959
21960            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21961                && !selections.is_empty()
21962            {
21963                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21964                // skip adding the initial selection to selection history
21965                self.selection_history.mode = SelectionHistoryMode::Skipping;
21966                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21967                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21968                        snapshot.clip_offset(start, Bias::Left)
21969                            ..snapshot.clip_offset(end, Bias::Right)
21970                    }));
21971                });
21972                self.selection_history.mode = SelectionHistoryMode::Normal;
21973            };
21974        }
21975
21976        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21977    }
21978
21979    fn update_lsp_data(
21980        &mut self,
21981        for_buffer: Option<BufferId>,
21982        window: &mut Window,
21983        cx: &mut Context<'_, Self>,
21984    ) {
21985        self.pull_diagnostics(for_buffer, window, cx);
21986        self.refresh_colors_for_visible_range(for_buffer, window, cx);
21987    }
21988
21989    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
21990        if self.ignore_lsp_data() {
21991            return;
21992        }
21993        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
21994            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
21995        }
21996    }
21997
21998    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
21999        if !self.registered_buffers.contains_key(&buffer_id)
22000            && let Some(project) = self.project.as_ref()
22001        {
22002            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22003                project.update(cx, |project, cx| {
22004                    self.registered_buffers.insert(
22005                        buffer_id,
22006                        project.register_buffer_with_language_servers(&buffer, cx),
22007                    );
22008                });
22009            } else {
22010                self.registered_buffers.remove(&buffer_id);
22011            }
22012        }
22013    }
22014
22015    fn ignore_lsp_data(&self) -> bool {
22016        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22017        // skip any LSP updates for it.
22018        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22019    }
22020}
22021
22022fn edit_for_markdown_paste<'a>(
22023    buffer: &MultiBufferSnapshot,
22024    range: Range<usize>,
22025    to_insert: &'a str,
22026    url: Option<url::Url>,
22027) -> (Range<usize>, Cow<'a, str>) {
22028    if url.is_none() {
22029        return (range, Cow::Borrowed(to_insert));
22030    };
22031
22032    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22033
22034    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22035        Cow::Borrowed(to_insert)
22036    } else {
22037        Cow::Owned(format!("[{old_text}]({to_insert})"))
22038    };
22039    (range, new_text)
22040}
22041
22042fn vim_enabled(cx: &App) -> bool {
22043    vim_mode_setting::VimModeSetting::try_get(cx)
22044        .map(|vim_mode| vim_mode.0)
22045        .unwrap_or(false)
22046}
22047
22048fn process_completion_for_edit(
22049    completion: &Completion,
22050    intent: CompletionIntent,
22051    buffer: &Entity<Buffer>,
22052    cursor_position: &text::Anchor,
22053    cx: &mut Context<Editor>,
22054) -> CompletionEdit {
22055    let buffer = buffer.read(cx);
22056    let buffer_snapshot = buffer.snapshot();
22057    let (snippet, new_text) = if completion.is_snippet() {
22058        let mut snippet_source = completion.new_text.clone();
22059        // Workaround for typescript language server issues so that methods don't expand within
22060        // strings and functions with type expressions. The previous point is used because the query
22061        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22062        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22063        let previous_point = if previous_point.column > 0 {
22064            cursor_position.to_previous_offset(&buffer_snapshot)
22065        } else {
22066            cursor_position.to_offset(&buffer_snapshot)
22067        };
22068        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22069            && scope.prefers_label_for_snippet_in_completion()
22070            && let Some(label) = completion.label()
22071            && matches!(
22072                completion.kind(),
22073                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22074            )
22075        {
22076            snippet_source = label;
22077        }
22078        match Snippet::parse(&snippet_source).log_err() {
22079            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22080            None => (None, completion.new_text.clone()),
22081        }
22082    } else {
22083        (None, completion.new_text.clone())
22084    };
22085
22086    let mut range_to_replace = {
22087        let replace_range = &completion.replace_range;
22088        if let CompletionSource::Lsp {
22089            insert_range: Some(insert_range),
22090            ..
22091        } = &completion.source
22092        {
22093            debug_assert_eq!(
22094                insert_range.start, replace_range.start,
22095                "insert_range and replace_range should start at the same position"
22096            );
22097            debug_assert!(
22098                insert_range
22099                    .start
22100                    .cmp(cursor_position, &buffer_snapshot)
22101                    .is_le(),
22102                "insert_range should start before or at cursor position"
22103            );
22104            debug_assert!(
22105                replace_range
22106                    .start
22107                    .cmp(cursor_position, &buffer_snapshot)
22108                    .is_le(),
22109                "replace_range should start before or at cursor position"
22110            );
22111
22112            let should_replace = match intent {
22113                CompletionIntent::CompleteWithInsert => false,
22114                CompletionIntent::CompleteWithReplace => true,
22115                CompletionIntent::Complete | CompletionIntent::Compose => {
22116                    let insert_mode =
22117                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22118                            .completions
22119                            .lsp_insert_mode;
22120                    match insert_mode {
22121                        LspInsertMode::Insert => false,
22122                        LspInsertMode::Replace => true,
22123                        LspInsertMode::ReplaceSubsequence => {
22124                            let mut text_to_replace = buffer.chars_for_range(
22125                                buffer.anchor_before(replace_range.start)
22126                                    ..buffer.anchor_after(replace_range.end),
22127                            );
22128                            let mut current_needle = text_to_replace.next();
22129                            for haystack_ch in completion.label.text.chars() {
22130                                if let Some(needle_ch) = current_needle
22131                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22132                                {
22133                                    current_needle = text_to_replace.next();
22134                                }
22135                            }
22136                            current_needle.is_none()
22137                        }
22138                        LspInsertMode::ReplaceSuffix => {
22139                            if replace_range
22140                                .end
22141                                .cmp(cursor_position, &buffer_snapshot)
22142                                .is_gt()
22143                            {
22144                                let range_after_cursor = *cursor_position..replace_range.end;
22145                                let text_after_cursor = buffer
22146                                    .text_for_range(
22147                                        buffer.anchor_before(range_after_cursor.start)
22148                                            ..buffer.anchor_after(range_after_cursor.end),
22149                                    )
22150                                    .collect::<String>()
22151                                    .to_ascii_lowercase();
22152                                completion
22153                                    .label
22154                                    .text
22155                                    .to_ascii_lowercase()
22156                                    .ends_with(&text_after_cursor)
22157                            } else {
22158                                true
22159                            }
22160                        }
22161                    }
22162                }
22163            };
22164
22165            if should_replace {
22166                replace_range.clone()
22167            } else {
22168                insert_range.clone()
22169            }
22170        } else {
22171            replace_range.clone()
22172        }
22173    };
22174
22175    if range_to_replace
22176        .end
22177        .cmp(cursor_position, &buffer_snapshot)
22178        .is_lt()
22179    {
22180        range_to_replace.end = *cursor_position;
22181    }
22182
22183    CompletionEdit {
22184        new_text,
22185        replace_range: range_to_replace.to_offset(buffer),
22186        snippet,
22187    }
22188}
22189
22190struct CompletionEdit {
22191    new_text: String,
22192    replace_range: Range<usize>,
22193    snippet: Option<Snippet>,
22194}
22195
22196fn insert_extra_newline_brackets(
22197    buffer: &MultiBufferSnapshot,
22198    range: Range<usize>,
22199    language: &language::LanguageScope,
22200) -> bool {
22201    let leading_whitespace_len = buffer
22202        .reversed_chars_at(range.start)
22203        .take_while(|c| c.is_whitespace() && *c != '\n')
22204        .map(|c| c.len_utf8())
22205        .sum::<usize>();
22206    let trailing_whitespace_len = buffer
22207        .chars_at(range.end)
22208        .take_while(|c| c.is_whitespace() && *c != '\n')
22209        .map(|c| c.len_utf8())
22210        .sum::<usize>();
22211    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22212
22213    language.brackets().any(|(pair, enabled)| {
22214        let pair_start = pair.start.trim_end();
22215        let pair_end = pair.end.trim_start();
22216
22217        enabled
22218            && pair.newline
22219            && buffer.contains_str_at(range.end, pair_end)
22220            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22221    })
22222}
22223
22224fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22225    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22226        [(buffer, range, _)] => (*buffer, range.clone()),
22227        _ => return false,
22228    };
22229    let pair = {
22230        let mut result: Option<BracketMatch> = None;
22231
22232        for pair in buffer
22233            .all_bracket_ranges(range.clone())
22234            .filter(move |pair| {
22235                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22236            })
22237        {
22238            let len = pair.close_range.end - pair.open_range.start;
22239
22240            if let Some(existing) = &result {
22241                let existing_len = existing.close_range.end - existing.open_range.start;
22242                if len > existing_len {
22243                    continue;
22244                }
22245            }
22246
22247            result = Some(pair);
22248        }
22249
22250        result
22251    };
22252    let Some(pair) = pair else {
22253        return false;
22254    };
22255    pair.newline_only
22256        && buffer
22257            .chars_for_range(pair.open_range.end..range.start)
22258            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22259            .all(|c| c.is_whitespace() && c != '\n')
22260}
22261
22262fn update_uncommitted_diff_for_buffer(
22263    editor: Entity<Editor>,
22264    project: &Entity<Project>,
22265    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22266    buffer: Entity<MultiBuffer>,
22267    cx: &mut App,
22268) -> Task<()> {
22269    let mut tasks = Vec::new();
22270    project.update(cx, |project, cx| {
22271        for buffer in buffers {
22272            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22273                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22274            }
22275        }
22276    });
22277    cx.spawn(async move |cx| {
22278        let diffs = future::join_all(tasks).await;
22279        if editor
22280            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22281            .unwrap_or(false)
22282        {
22283            return;
22284        }
22285
22286        buffer
22287            .update(cx, |buffer, cx| {
22288                for diff in diffs.into_iter().flatten() {
22289                    buffer.add_diff(diff, cx);
22290                }
22291            })
22292            .ok();
22293    })
22294}
22295
22296fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22297    let tab_size = tab_size.get() as usize;
22298    let mut width = offset;
22299
22300    for ch in text.chars() {
22301        width += if ch == '\t' {
22302            tab_size - (width % tab_size)
22303        } else {
22304            1
22305        };
22306    }
22307
22308    width - offset
22309}
22310
22311#[cfg(test)]
22312mod tests {
22313    use super::*;
22314
22315    #[test]
22316    fn test_string_size_with_expanded_tabs() {
22317        let nz = |val| NonZeroU32::new(val).unwrap();
22318        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22319        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22320        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22321        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22322        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22323        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22324        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22325        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22326    }
22327}
22328
22329/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22330struct WordBreakingTokenizer<'a> {
22331    input: &'a str,
22332}
22333
22334impl<'a> WordBreakingTokenizer<'a> {
22335    fn new(input: &'a str) -> Self {
22336        Self { input }
22337    }
22338}
22339
22340fn is_char_ideographic(ch: char) -> bool {
22341    use unicode_script::Script::*;
22342    use unicode_script::UnicodeScript;
22343    matches!(ch.script(), Han | Tangut | Yi)
22344}
22345
22346fn is_grapheme_ideographic(text: &str) -> bool {
22347    text.chars().any(is_char_ideographic)
22348}
22349
22350fn is_grapheme_whitespace(text: &str) -> bool {
22351    text.chars().any(|x| x.is_whitespace())
22352}
22353
22354fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22355    text.chars()
22356        .next()
22357        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22358}
22359
22360#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22361enum WordBreakToken<'a> {
22362    Word { token: &'a str, grapheme_len: usize },
22363    InlineWhitespace { token: &'a str, grapheme_len: usize },
22364    Newline,
22365}
22366
22367impl<'a> Iterator for WordBreakingTokenizer<'a> {
22368    /// Yields a span, the count of graphemes in the token, and whether it was
22369    /// whitespace. Note that it also breaks at word boundaries.
22370    type Item = WordBreakToken<'a>;
22371
22372    fn next(&mut self) -> Option<Self::Item> {
22373        use unicode_segmentation::UnicodeSegmentation;
22374        if self.input.is_empty() {
22375            return None;
22376        }
22377
22378        let mut iter = self.input.graphemes(true).peekable();
22379        let mut offset = 0;
22380        let mut grapheme_len = 0;
22381        if let Some(first_grapheme) = iter.next() {
22382            let is_newline = first_grapheme == "\n";
22383            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22384            offset += first_grapheme.len();
22385            grapheme_len += 1;
22386            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22387                if let Some(grapheme) = iter.peek().copied()
22388                    && should_stay_with_preceding_ideograph(grapheme)
22389                {
22390                    offset += grapheme.len();
22391                    grapheme_len += 1;
22392                }
22393            } else {
22394                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22395                let mut next_word_bound = words.peek().copied();
22396                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22397                    next_word_bound = words.next();
22398                }
22399                while let Some(grapheme) = iter.peek().copied() {
22400                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22401                        break;
22402                    };
22403                    if is_grapheme_whitespace(grapheme) != is_whitespace
22404                        || (grapheme == "\n") != is_newline
22405                    {
22406                        break;
22407                    };
22408                    offset += grapheme.len();
22409                    grapheme_len += 1;
22410                    iter.next();
22411                }
22412            }
22413            let token = &self.input[..offset];
22414            self.input = &self.input[offset..];
22415            if token == "\n" {
22416                Some(WordBreakToken::Newline)
22417            } else if is_whitespace {
22418                Some(WordBreakToken::InlineWhitespace {
22419                    token,
22420                    grapheme_len,
22421                })
22422            } else {
22423                Some(WordBreakToken::Word {
22424                    token,
22425                    grapheme_len,
22426                })
22427            }
22428        } else {
22429            None
22430        }
22431    }
22432}
22433
22434#[test]
22435fn test_word_breaking_tokenizer() {
22436    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22437        ("", &[]),
22438        ("  ", &[whitespace("  ", 2)]),
22439        ("Ʒ", &[word("Ʒ", 1)]),
22440        ("Ǽ", &[word("Ǽ", 1)]),
22441        ("", &[word("", 1)]),
22442        ("⋑⋑", &[word("⋑⋑", 2)]),
22443        (
22444            "原理,进而",
22445            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22446        ),
22447        (
22448            "hello world",
22449            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22450        ),
22451        (
22452            "hello, world",
22453            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22454        ),
22455        (
22456            "  hello world",
22457            &[
22458                whitespace("  ", 2),
22459                word("hello", 5),
22460                whitespace(" ", 1),
22461                word("world", 5),
22462            ],
22463        ),
22464        (
22465            "这是什么 \n 钢笔",
22466            &[
22467                word("", 1),
22468                word("", 1),
22469                word("", 1),
22470                word("", 1),
22471                whitespace(" ", 1),
22472                newline(),
22473                whitespace(" ", 1),
22474                word("", 1),
22475                word("", 1),
22476            ],
22477        ),
22478        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22479    ];
22480
22481    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22482        WordBreakToken::Word {
22483            token,
22484            grapheme_len,
22485        }
22486    }
22487
22488    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22489        WordBreakToken::InlineWhitespace {
22490            token,
22491            grapheme_len,
22492        }
22493    }
22494
22495    fn newline() -> WordBreakToken<'static> {
22496        WordBreakToken::Newline
22497    }
22498
22499    for (input, result) in tests {
22500        assert_eq!(
22501            WordBreakingTokenizer::new(input)
22502                .collect::<Vec<_>>()
22503                .as_slice(),
22504            *result,
22505        );
22506    }
22507}
22508
22509fn wrap_with_prefix(
22510    first_line_prefix: String,
22511    subsequent_lines_prefix: String,
22512    unwrapped_text: String,
22513    wrap_column: usize,
22514    tab_size: NonZeroU32,
22515    preserve_existing_whitespace: bool,
22516) -> String {
22517    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22518    let subsequent_lines_prefix_len =
22519        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22520    let mut wrapped_text = String::new();
22521    let mut current_line = first_line_prefix;
22522    let mut is_first_line = true;
22523
22524    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22525    let mut current_line_len = first_line_prefix_len;
22526    let mut in_whitespace = false;
22527    for token in tokenizer {
22528        let have_preceding_whitespace = in_whitespace;
22529        match token {
22530            WordBreakToken::Word {
22531                token,
22532                grapheme_len,
22533            } => {
22534                in_whitespace = false;
22535                let current_prefix_len = if is_first_line {
22536                    first_line_prefix_len
22537                } else {
22538                    subsequent_lines_prefix_len
22539                };
22540                if current_line_len + grapheme_len > wrap_column
22541                    && current_line_len != current_prefix_len
22542                {
22543                    wrapped_text.push_str(current_line.trim_end());
22544                    wrapped_text.push('\n');
22545                    is_first_line = false;
22546                    current_line = subsequent_lines_prefix.clone();
22547                    current_line_len = subsequent_lines_prefix_len;
22548                }
22549                current_line.push_str(token);
22550                current_line_len += grapheme_len;
22551            }
22552            WordBreakToken::InlineWhitespace {
22553                mut token,
22554                mut grapheme_len,
22555            } => {
22556                in_whitespace = true;
22557                if have_preceding_whitespace && !preserve_existing_whitespace {
22558                    continue;
22559                }
22560                if !preserve_existing_whitespace {
22561                    // Keep a single whitespace grapheme as-is
22562                    if let Some(first) =
22563                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22564                    {
22565                        token = first;
22566                    } else {
22567                        token = " ";
22568                    }
22569                    grapheme_len = 1;
22570                }
22571                let current_prefix_len = if is_first_line {
22572                    first_line_prefix_len
22573                } else {
22574                    subsequent_lines_prefix_len
22575                };
22576                if current_line_len + grapheme_len > wrap_column {
22577                    wrapped_text.push_str(current_line.trim_end());
22578                    wrapped_text.push('\n');
22579                    is_first_line = false;
22580                    current_line = subsequent_lines_prefix.clone();
22581                    current_line_len = subsequent_lines_prefix_len;
22582                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22583                    current_line.push_str(token);
22584                    current_line_len += grapheme_len;
22585                }
22586            }
22587            WordBreakToken::Newline => {
22588                in_whitespace = true;
22589                let current_prefix_len = if is_first_line {
22590                    first_line_prefix_len
22591                } else {
22592                    subsequent_lines_prefix_len
22593                };
22594                if preserve_existing_whitespace {
22595                    wrapped_text.push_str(current_line.trim_end());
22596                    wrapped_text.push('\n');
22597                    is_first_line = false;
22598                    current_line = subsequent_lines_prefix.clone();
22599                    current_line_len = subsequent_lines_prefix_len;
22600                } else if have_preceding_whitespace {
22601                    continue;
22602                } else if current_line_len + 1 > wrap_column
22603                    && current_line_len != current_prefix_len
22604                {
22605                    wrapped_text.push_str(current_line.trim_end());
22606                    wrapped_text.push('\n');
22607                    is_first_line = false;
22608                    current_line = subsequent_lines_prefix.clone();
22609                    current_line_len = subsequent_lines_prefix_len;
22610                } else if current_line_len != current_prefix_len {
22611                    current_line.push(' ');
22612                    current_line_len += 1;
22613                }
22614            }
22615        }
22616    }
22617
22618    if !current_line.is_empty() {
22619        wrapped_text.push_str(&current_line);
22620    }
22621    wrapped_text
22622}
22623
22624#[test]
22625fn test_wrap_with_prefix() {
22626    assert_eq!(
22627        wrap_with_prefix(
22628            "# ".to_string(),
22629            "# ".to_string(),
22630            "abcdefg".to_string(),
22631            4,
22632            NonZeroU32::new(4).unwrap(),
22633            false,
22634        ),
22635        "# abcdefg"
22636    );
22637    assert_eq!(
22638        wrap_with_prefix(
22639            "".to_string(),
22640            "".to_string(),
22641            "\thello world".to_string(),
22642            8,
22643            NonZeroU32::new(4).unwrap(),
22644            false,
22645        ),
22646        "hello\nworld"
22647    );
22648    assert_eq!(
22649        wrap_with_prefix(
22650            "// ".to_string(),
22651            "// ".to_string(),
22652            "xx \nyy zz aa bb cc".to_string(),
22653            12,
22654            NonZeroU32::new(4).unwrap(),
22655            false,
22656        ),
22657        "// xx yy zz\n// aa bb cc"
22658    );
22659    assert_eq!(
22660        wrap_with_prefix(
22661            String::new(),
22662            String::new(),
22663            "这是什么 \n 钢笔".to_string(),
22664            3,
22665            NonZeroU32::new(4).unwrap(),
22666            false,
22667        ),
22668        "这是什\n么 钢\n"
22669    );
22670    assert_eq!(
22671        wrap_with_prefix(
22672            String::new(),
22673            String::new(),
22674            format!("foo{}bar", '\u{2009}'), // thin space
22675            80,
22676            NonZeroU32::new(4).unwrap(),
22677            false,
22678        ),
22679        format!("foo{}bar", '\u{2009}')
22680    );
22681}
22682
22683pub trait CollaborationHub {
22684    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22685    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22686    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22687}
22688
22689impl CollaborationHub for Entity<Project> {
22690    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22691        self.read(cx).collaborators()
22692    }
22693
22694    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22695        self.read(cx).user_store().read(cx).participant_indices()
22696    }
22697
22698    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22699        let this = self.read(cx);
22700        let user_ids = this.collaborators().values().map(|c| c.user_id);
22701        this.user_store().read(cx).participant_names(user_ids, cx)
22702    }
22703}
22704
22705pub trait SemanticsProvider {
22706    fn hover(
22707        &self,
22708        buffer: &Entity<Buffer>,
22709        position: text::Anchor,
22710        cx: &mut App,
22711    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22712
22713    fn inline_values(
22714        &self,
22715        buffer_handle: Entity<Buffer>,
22716        range: Range<text::Anchor>,
22717        cx: &mut App,
22718    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22719
22720    fn applicable_inlay_chunks(
22721        &self,
22722        buffer: &Entity<Buffer>,
22723        ranges: &[Range<text::Anchor>],
22724        cx: &mut App,
22725    ) -> Vec<Range<BufferRow>>;
22726
22727    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22728
22729    fn inlay_hints(
22730        &self,
22731        invalidate: InvalidationStrategy,
22732        buffer: Entity<Buffer>,
22733        ranges: Vec<Range<text::Anchor>>,
22734        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22735        cx: &mut App,
22736    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22737
22738    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22739
22740    fn document_highlights(
22741        &self,
22742        buffer: &Entity<Buffer>,
22743        position: text::Anchor,
22744        cx: &mut App,
22745    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22746
22747    fn definitions(
22748        &self,
22749        buffer: &Entity<Buffer>,
22750        position: text::Anchor,
22751        kind: GotoDefinitionKind,
22752        cx: &mut App,
22753    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22754
22755    fn range_for_rename(
22756        &self,
22757        buffer: &Entity<Buffer>,
22758        position: text::Anchor,
22759        cx: &mut App,
22760    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22761
22762    fn perform_rename(
22763        &self,
22764        buffer: &Entity<Buffer>,
22765        position: text::Anchor,
22766        new_name: String,
22767        cx: &mut App,
22768    ) -> Option<Task<Result<ProjectTransaction>>>;
22769}
22770
22771pub trait CompletionProvider {
22772    fn completions(
22773        &self,
22774        excerpt_id: ExcerptId,
22775        buffer: &Entity<Buffer>,
22776        buffer_position: text::Anchor,
22777        trigger: CompletionContext,
22778        window: &mut Window,
22779        cx: &mut Context<Editor>,
22780    ) -> Task<Result<Vec<CompletionResponse>>>;
22781
22782    fn resolve_completions(
22783        &self,
22784        _buffer: Entity<Buffer>,
22785        _completion_indices: Vec<usize>,
22786        _completions: Rc<RefCell<Box<[Completion]>>>,
22787        _cx: &mut Context<Editor>,
22788    ) -> Task<Result<bool>> {
22789        Task::ready(Ok(false))
22790    }
22791
22792    fn apply_additional_edits_for_completion(
22793        &self,
22794        _buffer: Entity<Buffer>,
22795        _completions: Rc<RefCell<Box<[Completion]>>>,
22796        _completion_index: usize,
22797        _push_to_history: bool,
22798        _cx: &mut Context<Editor>,
22799    ) -> Task<Result<Option<language::Transaction>>> {
22800        Task::ready(Ok(None))
22801    }
22802
22803    fn is_completion_trigger(
22804        &self,
22805        buffer: &Entity<Buffer>,
22806        position: language::Anchor,
22807        text: &str,
22808        trigger_in_words: bool,
22809        menu_is_open: bool,
22810        cx: &mut Context<Editor>,
22811    ) -> bool;
22812
22813    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22814
22815    fn sort_completions(&self) -> bool {
22816        true
22817    }
22818
22819    fn filter_completions(&self) -> bool {
22820        true
22821    }
22822}
22823
22824pub trait CodeActionProvider {
22825    fn id(&self) -> Arc<str>;
22826
22827    fn code_actions(
22828        &self,
22829        buffer: &Entity<Buffer>,
22830        range: Range<text::Anchor>,
22831        window: &mut Window,
22832        cx: &mut App,
22833    ) -> Task<Result<Vec<CodeAction>>>;
22834
22835    fn apply_code_action(
22836        &self,
22837        buffer_handle: Entity<Buffer>,
22838        action: CodeAction,
22839        excerpt_id: ExcerptId,
22840        push_to_history: bool,
22841        window: &mut Window,
22842        cx: &mut App,
22843    ) -> Task<Result<ProjectTransaction>>;
22844}
22845
22846impl CodeActionProvider for Entity<Project> {
22847    fn id(&self) -> Arc<str> {
22848        "project".into()
22849    }
22850
22851    fn code_actions(
22852        &self,
22853        buffer: &Entity<Buffer>,
22854        range: Range<text::Anchor>,
22855        _window: &mut Window,
22856        cx: &mut App,
22857    ) -> Task<Result<Vec<CodeAction>>> {
22858        self.update(cx, |project, cx| {
22859            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22860            let code_actions = project.code_actions(buffer, range, None, cx);
22861            cx.background_spawn(async move {
22862                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22863                Ok(code_lens_actions
22864                    .context("code lens fetch")?
22865                    .into_iter()
22866                    .flatten()
22867                    .chain(
22868                        code_actions
22869                            .context("code action fetch")?
22870                            .into_iter()
22871                            .flatten(),
22872                    )
22873                    .collect())
22874            })
22875        })
22876    }
22877
22878    fn apply_code_action(
22879        &self,
22880        buffer_handle: Entity<Buffer>,
22881        action: CodeAction,
22882        _excerpt_id: ExcerptId,
22883        push_to_history: bool,
22884        _window: &mut Window,
22885        cx: &mut App,
22886    ) -> Task<Result<ProjectTransaction>> {
22887        self.update(cx, |project, cx| {
22888            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22889        })
22890    }
22891}
22892
22893fn snippet_completions(
22894    project: &Project,
22895    buffer: &Entity<Buffer>,
22896    buffer_position: text::Anchor,
22897    cx: &mut App,
22898) -> Task<Result<CompletionResponse>> {
22899    let languages = buffer.read(cx).languages_at(buffer_position);
22900    let snippet_store = project.snippets().read(cx);
22901
22902    let scopes: Vec<_> = languages
22903        .iter()
22904        .filter_map(|language| {
22905            let language_name = language.lsp_id();
22906            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22907
22908            if snippets.is_empty() {
22909                None
22910            } else {
22911                Some((language.default_scope(), snippets))
22912            }
22913        })
22914        .collect();
22915
22916    if scopes.is_empty() {
22917        return Task::ready(Ok(CompletionResponse {
22918            completions: vec![],
22919            display_options: CompletionDisplayOptions::default(),
22920            is_incomplete: false,
22921        }));
22922    }
22923
22924    let snapshot = buffer.read(cx).text_snapshot();
22925    let executor = cx.background_executor().clone();
22926
22927    cx.background_spawn(async move {
22928        let mut is_incomplete = false;
22929        let mut completions: Vec<Completion> = Vec::new();
22930        for (scope, snippets) in scopes.into_iter() {
22931            let classifier =
22932                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22933
22934            const MAX_WORD_PREFIX_LEN: usize = 128;
22935            let last_word: String = snapshot
22936                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22937                .take(MAX_WORD_PREFIX_LEN)
22938                .take_while(|c| classifier.is_word(*c))
22939                .collect::<String>()
22940                .chars()
22941                .rev()
22942                .collect();
22943
22944            if last_word.is_empty() {
22945                return Ok(CompletionResponse {
22946                    completions: vec![],
22947                    display_options: CompletionDisplayOptions::default(),
22948                    is_incomplete: true,
22949                });
22950            }
22951
22952            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22953            let to_lsp = |point: &text::Anchor| {
22954                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22955                point_to_lsp(end)
22956            };
22957            let lsp_end = to_lsp(&buffer_position);
22958
22959            let candidates = snippets
22960                .iter()
22961                .enumerate()
22962                .flat_map(|(ix, snippet)| {
22963                    snippet
22964                        .prefix
22965                        .iter()
22966                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22967                })
22968                .collect::<Vec<StringMatchCandidate>>();
22969
22970            const MAX_RESULTS: usize = 100;
22971            let mut matches = fuzzy::match_strings(
22972                &candidates,
22973                &last_word,
22974                last_word.chars().any(|c| c.is_uppercase()),
22975                true,
22976                MAX_RESULTS,
22977                &Default::default(),
22978                executor.clone(),
22979            )
22980            .await;
22981
22982            if matches.len() >= MAX_RESULTS {
22983                is_incomplete = true;
22984            }
22985
22986            // Remove all candidates where the query's start does not match the start of any word in the candidate
22987            if let Some(query_start) = last_word.chars().next() {
22988                matches.retain(|string_match| {
22989                    split_words(&string_match.string).any(|word| {
22990                        // Check that the first codepoint of the word as lowercase matches the first
22991                        // codepoint of the query as lowercase
22992                        word.chars()
22993                            .flat_map(|codepoint| codepoint.to_lowercase())
22994                            .zip(query_start.to_lowercase())
22995                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22996                    })
22997                });
22998            }
22999
23000            let matched_strings = matches
23001                .into_iter()
23002                .map(|m| m.string)
23003                .collect::<HashSet<_>>();
23004
23005            completions.extend(snippets.iter().filter_map(|snippet| {
23006                let matching_prefix = snippet
23007                    .prefix
23008                    .iter()
23009                    .find(|prefix| matched_strings.contains(*prefix))?;
23010                let start = as_offset - last_word.len();
23011                let start = snapshot.anchor_before(start);
23012                let range = start..buffer_position;
23013                let lsp_start = to_lsp(&start);
23014                let lsp_range = lsp::Range {
23015                    start: lsp_start,
23016                    end: lsp_end,
23017                };
23018                Some(Completion {
23019                    replace_range: range,
23020                    new_text: snippet.body.clone(),
23021                    source: CompletionSource::Lsp {
23022                        insert_range: None,
23023                        server_id: LanguageServerId(usize::MAX),
23024                        resolved: true,
23025                        lsp_completion: Box::new(lsp::CompletionItem {
23026                            label: snippet.prefix.first().unwrap().clone(),
23027                            kind: Some(CompletionItemKind::SNIPPET),
23028                            label_details: snippet.description.as_ref().map(|description| {
23029                                lsp::CompletionItemLabelDetails {
23030                                    detail: Some(description.clone()),
23031                                    description: None,
23032                                }
23033                            }),
23034                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23035                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23036                                lsp::InsertReplaceEdit {
23037                                    new_text: snippet.body.clone(),
23038                                    insert: lsp_range,
23039                                    replace: lsp_range,
23040                                },
23041                            )),
23042                            filter_text: Some(snippet.body.clone()),
23043                            sort_text: Some(char::MAX.to_string()),
23044                            ..lsp::CompletionItem::default()
23045                        }),
23046                        lsp_defaults: None,
23047                    },
23048                    label: CodeLabel::plain(matching_prefix.clone(), None),
23049                    icon_path: None,
23050                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23051                        single_line: snippet.name.clone().into(),
23052                        plain_text: snippet
23053                            .description
23054                            .clone()
23055                            .map(|description| description.into()),
23056                    }),
23057                    insert_text_mode: None,
23058                    confirm: None,
23059                })
23060            }))
23061        }
23062
23063        Ok(CompletionResponse {
23064            completions,
23065            display_options: CompletionDisplayOptions::default(),
23066            is_incomplete,
23067        })
23068    })
23069}
23070
23071impl CompletionProvider for Entity<Project> {
23072    fn completions(
23073        &self,
23074        _excerpt_id: ExcerptId,
23075        buffer: &Entity<Buffer>,
23076        buffer_position: text::Anchor,
23077        options: CompletionContext,
23078        _window: &mut Window,
23079        cx: &mut Context<Editor>,
23080    ) -> Task<Result<Vec<CompletionResponse>>> {
23081        self.update(cx, |project, cx| {
23082            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23083            let project_completions = project.completions(buffer, buffer_position, options, cx);
23084            cx.background_spawn(async move {
23085                let mut responses = project_completions.await?;
23086                let snippets = snippets.await?;
23087                if !snippets.completions.is_empty() {
23088                    responses.push(snippets);
23089                }
23090                Ok(responses)
23091            })
23092        })
23093    }
23094
23095    fn resolve_completions(
23096        &self,
23097        buffer: Entity<Buffer>,
23098        completion_indices: Vec<usize>,
23099        completions: Rc<RefCell<Box<[Completion]>>>,
23100        cx: &mut Context<Editor>,
23101    ) -> Task<Result<bool>> {
23102        self.update(cx, |project, cx| {
23103            project.lsp_store().update(cx, |lsp_store, cx| {
23104                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23105            })
23106        })
23107    }
23108
23109    fn apply_additional_edits_for_completion(
23110        &self,
23111        buffer: Entity<Buffer>,
23112        completions: Rc<RefCell<Box<[Completion]>>>,
23113        completion_index: usize,
23114        push_to_history: bool,
23115        cx: &mut Context<Editor>,
23116    ) -> Task<Result<Option<language::Transaction>>> {
23117        self.update(cx, |project, cx| {
23118            project.lsp_store().update(cx, |lsp_store, cx| {
23119                lsp_store.apply_additional_edits_for_completion(
23120                    buffer,
23121                    completions,
23122                    completion_index,
23123                    push_to_history,
23124                    cx,
23125                )
23126            })
23127        })
23128    }
23129
23130    fn is_completion_trigger(
23131        &self,
23132        buffer: &Entity<Buffer>,
23133        position: language::Anchor,
23134        text: &str,
23135        trigger_in_words: bool,
23136        menu_is_open: bool,
23137        cx: &mut Context<Editor>,
23138    ) -> bool {
23139        let mut chars = text.chars();
23140        let char = if let Some(char) = chars.next() {
23141            char
23142        } else {
23143            return false;
23144        };
23145        if chars.next().is_some() {
23146            return false;
23147        }
23148
23149        let buffer = buffer.read(cx);
23150        let snapshot = buffer.snapshot();
23151        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23152            return false;
23153        }
23154        let classifier = snapshot
23155            .char_classifier_at(position)
23156            .scope_context(Some(CharScopeContext::Completion));
23157        if trigger_in_words && classifier.is_word(char) {
23158            return true;
23159        }
23160
23161        buffer.completion_triggers().contains(text)
23162    }
23163}
23164
23165impl SemanticsProvider for Entity<Project> {
23166    fn hover(
23167        &self,
23168        buffer: &Entity<Buffer>,
23169        position: text::Anchor,
23170        cx: &mut App,
23171    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23172        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23173    }
23174
23175    fn document_highlights(
23176        &self,
23177        buffer: &Entity<Buffer>,
23178        position: text::Anchor,
23179        cx: &mut App,
23180    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23181        Some(self.update(cx, |project, cx| {
23182            project.document_highlights(buffer, position, cx)
23183        }))
23184    }
23185
23186    fn definitions(
23187        &self,
23188        buffer: &Entity<Buffer>,
23189        position: text::Anchor,
23190        kind: GotoDefinitionKind,
23191        cx: &mut App,
23192    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23193        Some(self.update(cx, |project, cx| match kind {
23194            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23195            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23196            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23197            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23198        }))
23199    }
23200
23201    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23202        self.update(cx, |project, cx| {
23203            if project
23204                .active_debug_session(cx)
23205                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23206            {
23207                return true;
23208            }
23209
23210            buffer.update(cx, |buffer, cx| {
23211                project.any_language_server_supports_inlay_hints(buffer, cx)
23212            })
23213        })
23214    }
23215
23216    fn inline_values(
23217        &self,
23218        buffer_handle: Entity<Buffer>,
23219        range: Range<text::Anchor>,
23220        cx: &mut App,
23221    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23222        self.update(cx, |project, cx| {
23223            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23224
23225            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23226        })
23227    }
23228
23229    fn applicable_inlay_chunks(
23230        &self,
23231        buffer: &Entity<Buffer>,
23232        ranges: &[Range<text::Anchor>],
23233        cx: &mut App,
23234    ) -> Vec<Range<BufferRow>> {
23235        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23236            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23237        })
23238    }
23239
23240    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23241        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23242            lsp_store.invalidate_inlay_hints(for_buffers)
23243        });
23244    }
23245
23246    fn inlay_hints(
23247        &self,
23248        invalidate: InvalidationStrategy,
23249        buffer: Entity<Buffer>,
23250        ranges: Vec<Range<text::Anchor>>,
23251        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23252        cx: &mut App,
23253    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23254        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23255            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23256        }))
23257    }
23258
23259    fn range_for_rename(
23260        &self,
23261        buffer: &Entity<Buffer>,
23262        position: text::Anchor,
23263        cx: &mut App,
23264    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23265        Some(self.update(cx, |project, cx| {
23266            let buffer = buffer.clone();
23267            let task = project.prepare_rename(buffer.clone(), position, cx);
23268            cx.spawn(async move |_, cx| {
23269                Ok(match task.await? {
23270                    PrepareRenameResponse::Success(range) => Some(range),
23271                    PrepareRenameResponse::InvalidPosition => None,
23272                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23273                        // Fallback on using TreeSitter info to determine identifier range
23274                        buffer.read_with(cx, |buffer, _| {
23275                            let snapshot = buffer.snapshot();
23276                            let (range, kind) = snapshot.surrounding_word(position, None);
23277                            if kind != Some(CharKind::Word) {
23278                                return None;
23279                            }
23280                            Some(
23281                                snapshot.anchor_before(range.start)
23282                                    ..snapshot.anchor_after(range.end),
23283                            )
23284                        })?
23285                    }
23286                })
23287            })
23288        }))
23289    }
23290
23291    fn perform_rename(
23292        &self,
23293        buffer: &Entity<Buffer>,
23294        position: text::Anchor,
23295        new_name: String,
23296        cx: &mut App,
23297    ) -> Option<Task<Result<ProjectTransaction>>> {
23298        Some(self.update(cx, |project, cx| {
23299            project.perform_rename(buffer.clone(), position, new_name, cx)
23300        }))
23301    }
23302}
23303
23304fn consume_contiguous_rows(
23305    contiguous_row_selections: &mut Vec<Selection<Point>>,
23306    selection: &Selection<Point>,
23307    display_map: &DisplaySnapshot,
23308    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23309) -> (MultiBufferRow, MultiBufferRow) {
23310    contiguous_row_selections.push(selection.clone());
23311    let start_row = starting_row(selection, display_map);
23312    let mut end_row = ending_row(selection, display_map);
23313
23314    while let Some(next_selection) = selections.peek() {
23315        if next_selection.start.row <= end_row.0 {
23316            end_row = ending_row(next_selection, display_map);
23317            contiguous_row_selections.push(selections.next().unwrap().clone());
23318        } else {
23319            break;
23320        }
23321    }
23322    (start_row, end_row)
23323}
23324
23325fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23326    if selection.start.column > 0 {
23327        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23328    } else {
23329        MultiBufferRow(selection.start.row)
23330    }
23331}
23332
23333fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23334    if next_selection.end.column > 0 || next_selection.is_empty() {
23335        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23336    } else {
23337        MultiBufferRow(next_selection.end.row)
23338    }
23339}
23340
23341impl EditorSnapshot {
23342    pub fn remote_selections_in_range<'a>(
23343        &'a self,
23344        range: &'a Range<Anchor>,
23345        collaboration_hub: &dyn CollaborationHub,
23346        cx: &'a App,
23347    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23348        let participant_names = collaboration_hub.user_names(cx);
23349        let participant_indices = collaboration_hub.user_participant_indices(cx);
23350        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23351        let collaborators_by_replica_id = collaborators_by_peer_id
23352            .values()
23353            .map(|collaborator| (collaborator.replica_id, collaborator))
23354            .collect::<HashMap<_, _>>();
23355        self.buffer_snapshot()
23356            .selections_in_range(range, false)
23357            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23358                if replica_id == ReplicaId::AGENT {
23359                    Some(RemoteSelection {
23360                        replica_id,
23361                        selection,
23362                        cursor_shape,
23363                        line_mode,
23364                        collaborator_id: CollaboratorId::Agent,
23365                        user_name: Some("Agent".into()),
23366                        color: cx.theme().players().agent(),
23367                    })
23368                } else {
23369                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23370                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23371                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23372                    Some(RemoteSelection {
23373                        replica_id,
23374                        selection,
23375                        cursor_shape,
23376                        line_mode,
23377                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23378                        user_name,
23379                        color: if let Some(index) = participant_index {
23380                            cx.theme().players().color_for_participant(index.0)
23381                        } else {
23382                            cx.theme().players().absent()
23383                        },
23384                    })
23385                }
23386            })
23387    }
23388
23389    pub fn hunks_for_ranges(
23390        &self,
23391        ranges: impl IntoIterator<Item = Range<Point>>,
23392    ) -> Vec<MultiBufferDiffHunk> {
23393        let mut hunks = Vec::new();
23394        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23395            HashMap::default();
23396        for query_range in ranges {
23397            let query_rows =
23398                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23399            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23400                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23401            ) {
23402                // Include deleted hunks that are adjacent to the query range, because
23403                // otherwise they would be missed.
23404                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23405                if hunk.status().is_deleted() {
23406                    intersects_range |= hunk.row_range.start == query_rows.end;
23407                    intersects_range |= hunk.row_range.end == query_rows.start;
23408                }
23409                if intersects_range {
23410                    if !processed_buffer_rows
23411                        .entry(hunk.buffer_id)
23412                        .or_default()
23413                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23414                    {
23415                        continue;
23416                    }
23417                    hunks.push(hunk);
23418                }
23419            }
23420        }
23421
23422        hunks
23423    }
23424
23425    fn display_diff_hunks_for_rows<'a>(
23426        &'a self,
23427        display_rows: Range<DisplayRow>,
23428        folded_buffers: &'a HashSet<BufferId>,
23429    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23430        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23431        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23432
23433        self.buffer_snapshot()
23434            .diff_hunks_in_range(buffer_start..buffer_end)
23435            .filter_map(|hunk| {
23436                if folded_buffers.contains(&hunk.buffer_id) {
23437                    return None;
23438                }
23439
23440                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23441                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23442
23443                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23444                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23445
23446                let display_hunk = if hunk_display_start.column() != 0 {
23447                    DisplayDiffHunk::Folded {
23448                        display_row: hunk_display_start.row(),
23449                    }
23450                } else {
23451                    let mut end_row = hunk_display_end.row();
23452                    if hunk_display_end.column() > 0 {
23453                        end_row.0 += 1;
23454                    }
23455                    let is_created_file = hunk.is_created_file();
23456                    DisplayDiffHunk::Unfolded {
23457                        status: hunk.status(),
23458                        diff_base_byte_range: hunk.diff_base_byte_range,
23459                        display_row_range: hunk_display_start.row()..end_row,
23460                        multi_buffer_range: Anchor::range_in_buffer(
23461                            hunk.excerpt_id,
23462                            hunk.buffer_id,
23463                            hunk.buffer_range,
23464                        ),
23465                        is_created_file,
23466                    }
23467                };
23468
23469                Some(display_hunk)
23470            })
23471    }
23472
23473    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23474        self.display_snapshot
23475            .buffer_snapshot()
23476            .language_at(position)
23477    }
23478
23479    pub fn is_focused(&self) -> bool {
23480        self.is_focused
23481    }
23482
23483    pub fn placeholder_text(&self) -> Option<String> {
23484        self.placeholder_display_snapshot
23485            .as_ref()
23486            .map(|display_map| display_map.text())
23487    }
23488
23489    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23490        self.scroll_anchor.scroll_position(&self.display_snapshot)
23491    }
23492
23493    fn gutter_dimensions(
23494        &self,
23495        font_id: FontId,
23496        font_size: Pixels,
23497        max_line_number_width: Pixels,
23498        cx: &App,
23499    ) -> Option<GutterDimensions> {
23500        if !self.show_gutter {
23501            return None;
23502        }
23503
23504        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23505        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23506
23507        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23508            matches!(
23509                ProjectSettings::get_global(cx).git.git_gutter,
23510                GitGutterSetting::TrackedFiles
23511            )
23512        });
23513        let gutter_settings = EditorSettings::get_global(cx).gutter;
23514        let show_line_numbers = self
23515            .show_line_numbers
23516            .unwrap_or(gutter_settings.line_numbers);
23517        let line_gutter_width = if show_line_numbers {
23518            // Avoid flicker-like gutter resizes when the line number gains another digit by
23519            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23520            let min_width_for_number_on_gutter =
23521                ch_advance * gutter_settings.min_line_number_digits as f32;
23522            max_line_number_width.max(min_width_for_number_on_gutter)
23523        } else {
23524            0.0.into()
23525        };
23526
23527        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23528        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23529
23530        let git_blame_entries_width =
23531            self.git_blame_gutter_max_author_length
23532                .map(|max_author_length| {
23533                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23534                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23535
23536                    /// The number of characters to dedicate to gaps and margins.
23537                    const SPACING_WIDTH: usize = 4;
23538
23539                    let max_char_count = max_author_length.min(renderer.max_author_length())
23540                        + ::git::SHORT_SHA_LENGTH
23541                        + MAX_RELATIVE_TIMESTAMP.len()
23542                        + SPACING_WIDTH;
23543
23544                    ch_advance * max_char_count
23545                });
23546
23547        let is_singleton = self.buffer_snapshot().is_singleton();
23548
23549        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23550        left_padding += if !is_singleton {
23551            ch_width * 4.0
23552        } else if show_runnables || show_breakpoints {
23553            ch_width * 3.0
23554        } else if show_git_gutter && show_line_numbers {
23555            ch_width * 2.0
23556        } else if show_git_gutter || show_line_numbers {
23557            ch_width
23558        } else {
23559            px(0.)
23560        };
23561
23562        let shows_folds = is_singleton && gutter_settings.folds;
23563
23564        let right_padding = if shows_folds && show_line_numbers {
23565            ch_width * 4.0
23566        } else if shows_folds || (!is_singleton && show_line_numbers) {
23567            ch_width * 3.0
23568        } else if show_line_numbers {
23569            ch_width
23570        } else {
23571            px(0.)
23572        };
23573
23574        Some(GutterDimensions {
23575            left_padding,
23576            right_padding,
23577            width: line_gutter_width + left_padding + right_padding,
23578            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23579            git_blame_entries_width,
23580        })
23581    }
23582
23583    pub fn render_crease_toggle(
23584        &self,
23585        buffer_row: MultiBufferRow,
23586        row_contains_cursor: bool,
23587        editor: Entity<Editor>,
23588        window: &mut Window,
23589        cx: &mut App,
23590    ) -> Option<AnyElement> {
23591        let folded = self.is_line_folded(buffer_row);
23592        let mut is_foldable = false;
23593
23594        if let Some(crease) = self
23595            .crease_snapshot
23596            .query_row(buffer_row, self.buffer_snapshot())
23597        {
23598            is_foldable = true;
23599            match crease {
23600                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23601                    if let Some(render_toggle) = render_toggle {
23602                        let toggle_callback =
23603                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23604                                if folded {
23605                                    editor.update(cx, |editor, cx| {
23606                                        editor.fold_at(buffer_row, window, cx)
23607                                    });
23608                                } else {
23609                                    editor.update(cx, |editor, cx| {
23610                                        editor.unfold_at(buffer_row, window, cx)
23611                                    });
23612                                }
23613                            });
23614                        return Some((render_toggle)(
23615                            buffer_row,
23616                            folded,
23617                            toggle_callback,
23618                            window,
23619                            cx,
23620                        ));
23621                    }
23622                }
23623            }
23624        }
23625
23626        is_foldable |= self.starts_indent(buffer_row);
23627
23628        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23629            Some(
23630                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23631                    .toggle_state(folded)
23632                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23633                        if folded {
23634                            this.unfold_at(buffer_row, window, cx);
23635                        } else {
23636                            this.fold_at(buffer_row, window, cx);
23637                        }
23638                    }))
23639                    .into_any_element(),
23640            )
23641        } else {
23642            None
23643        }
23644    }
23645
23646    pub fn render_crease_trailer(
23647        &self,
23648        buffer_row: MultiBufferRow,
23649        window: &mut Window,
23650        cx: &mut App,
23651    ) -> Option<AnyElement> {
23652        let folded = self.is_line_folded(buffer_row);
23653        if let Crease::Inline { render_trailer, .. } = self
23654            .crease_snapshot
23655            .query_row(buffer_row, self.buffer_snapshot())?
23656        {
23657            let render_trailer = render_trailer.as_ref()?;
23658            Some(render_trailer(buffer_row, folded, window, cx))
23659        } else {
23660            None
23661        }
23662    }
23663}
23664
23665impl Deref for EditorSnapshot {
23666    type Target = DisplaySnapshot;
23667
23668    fn deref(&self) -> &Self::Target {
23669        &self.display_snapshot
23670    }
23671}
23672
23673#[derive(Clone, Debug, PartialEq, Eq)]
23674pub enum EditorEvent {
23675    InputIgnored {
23676        text: Arc<str>,
23677    },
23678    InputHandled {
23679        utf16_range_to_replace: Option<Range<isize>>,
23680        text: Arc<str>,
23681    },
23682    ExcerptsAdded {
23683        buffer: Entity<Buffer>,
23684        predecessor: ExcerptId,
23685        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23686    },
23687    ExcerptsRemoved {
23688        ids: Vec<ExcerptId>,
23689        removed_buffer_ids: Vec<BufferId>,
23690    },
23691    BufferFoldToggled {
23692        ids: Vec<ExcerptId>,
23693        folded: bool,
23694    },
23695    ExcerptsEdited {
23696        ids: Vec<ExcerptId>,
23697    },
23698    ExcerptsExpanded {
23699        ids: Vec<ExcerptId>,
23700    },
23701    BufferEdited,
23702    Edited {
23703        transaction_id: clock::Lamport,
23704    },
23705    Reparsed(BufferId),
23706    Focused,
23707    FocusedIn,
23708    Blurred,
23709    DirtyChanged,
23710    Saved,
23711    TitleChanged,
23712    SelectionsChanged {
23713        local: bool,
23714    },
23715    ScrollPositionChanged {
23716        local: bool,
23717        autoscroll: bool,
23718    },
23719    TransactionUndone {
23720        transaction_id: clock::Lamport,
23721    },
23722    TransactionBegun {
23723        transaction_id: clock::Lamport,
23724    },
23725    CursorShapeChanged,
23726    BreadcrumbsChanged,
23727    PushedToNavHistory {
23728        anchor: Anchor,
23729        is_deactivate: bool,
23730    },
23731}
23732
23733impl EventEmitter<EditorEvent> for Editor {}
23734
23735impl Focusable for Editor {
23736    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23737        self.focus_handle.clone()
23738    }
23739}
23740
23741impl Render for Editor {
23742    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23743        let settings = ThemeSettings::get_global(cx);
23744
23745        let mut text_style = match self.mode {
23746            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23747                color: cx.theme().colors().editor_foreground,
23748                font_family: settings.ui_font.family.clone(),
23749                font_features: settings.ui_font.features.clone(),
23750                font_fallbacks: settings.ui_font.fallbacks.clone(),
23751                font_size: rems(0.875).into(),
23752                font_weight: settings.ui_font.weight,
23753                line_height: relative(settings.buffer_line_height.value()),
23754                ..Default::default()
23755            },
23756            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23757                color: cx.theme().colors().editor_foreground,
23758                font_family: settings.buffer_font.family.clone(),
23759                font_features: settings.buffer_font.features.clone(),
23760                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23761                font_size: settings.buffer_font_size(cx).into(),
23762                font_weight: settings.buffer_font.weight,
23763                line_height: relative(settings.buffer_line_height.value()),
23764                ..Default::default()
23765            },
23766        };
23767        if let Some(text_style_refinement) = &self.text_style_refinement {
23768            text_style.refine(text_style_refinement)
23769        }
23770
23771        let background = match self.mode {
23772            EditorMode::SingleLine => cx.theme().system().transparent,
23773            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23774            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23775            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23776        };
23777
23778        EditorElement::new(
23779            &cx.entity(),
23780            EditorStyle {
23781                background,
23782                border: cx.theme().colors().border,
23783                local_player: cx.theme().players().local(),
23784                text: text_style,
23785                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23786                syntax: cx.theme().syntax().clone(),
23787                status: cx.theme().status().clone(),
23788                inlay_hints_style: make_inlay_hints_style(cx),
23789                edit_prediction_styles: make_suggestion_styles(cx),
23790                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23791                show_underlines: self.diagnostics_enabled(),
23792            },
23793        )
23794    }
23795}
23796
23797impl EntityInputHandler for Editor {
23798    fn text_for_range(
23799        &mut self,
23800        range_utf16: Range<usize>,
23801        adjusted_range: &mut Option<Range<usize>>,
23802        _: &mut Window,
23803        cx: &mut Context<Self>,
23804    ) -> Option<String> {
23805        let snapshot = self.buffer.read(cx).read(cx);
23806        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23807        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23808        if (start.0..end.0) != range_utf16 {
23809            adjusted_range.replace(start.0..end.0);
23810        }
23811        Some(snapshot.text_for_range(start..end).collect())
23812    }
23813
23814    fn selected_text_range(
23815        &mut self,
23816        ignore_disabled_input: bool,
23817        _: &mut Window,
23818        cx: &mut Context<Self>,
23819    ) -> Option<UTF16Selection> {
23820        // Prevent the IME menu from appearing when holding down an alphabetic key
23821        // while input is disabled.
23822        if !ignore_disabled_input && !self.input_enabled {
23823            return None;
23824        }
23825
23826        let selection = self
23827            .selections
23828            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23829        let range = selection.range();
23830
23831        Some(UTF16Selection {
23832            range: range.start.0..range.end.0,
23833            reversed: selection.reversed,
23834        })
23835    }
23836
23837    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23838        let snapshot = self.buffer.read(cx).read(cx);
23839        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23840        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23841    }
23842
23843    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23844        self.clear_highlights::<InputComposition>(cx);
23845        self.ime_transaction.take();
23846    }
23847
23848    fn replace_text_in_range(
23849        &mut self,
23850        range_utf16: Option<Range<usize>>,
23851        text: &str,
23852        window: &mut Window,
23853        cx: &mut Context<Self>,
23854    ) {
23855        if !self.input_enabled {
23856            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23857            return;
23858        }
23859
23860        self.transact(window, cx, |this, window, cx| {
23861            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23862                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23863                Some(this.selection_replacement_ranges(range_utf16, cx))
23864            } else {
23865                this.marked_text_ranges(cx)
23866            };
23867
23868            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23869                let newest_selection_id = this.selections.newest_anchor().id;
23870                this.selections
23871                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23872                    .iter()
23873                    .zip(ranges_to_replace.iter())
23874                    .find_map(|(selection, range)| {
23875                        if selection.id == newest_selection_id {
23876                            Some(
23877                                (range.start.0 as isize - selection.head().0 as isize)
23878                                    ..(range.end.0 as isize - selection.head().0 as isize),
23879                            )
23880                        } else {
23881                            None
23882                        }
23883                    })
23884            });
23885
23886            cx.emit(EditorEvent::InputHandled {
23887                utf16_range_to_replace: range_to_replace,
23888                text: text.into(),
23889            });
23890
23891            if let Some(new_selected_ranges) = new_selected_ranges {
23892                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23893                    selections.select_ranges(new_selected_ranges)
23894                });
23895                this.backspace(&Default::default(), window, cx);
23896            }
23897
23898            this.handle_input(text, window, cx);
23899        });
23900
23901        if let Some(transaction) = self.ime_transaction {
23902            self.buffer.update(cx, |buffer, cx| {
23903                buffer.group_until_transaction(transaction, cx);
23904            });
23905        }
23906
23907        self.unmark_text(window, cx);
23908    }
23909
23910    fn replace_and_mark_text_in_range(
23911        &mut self,
23912        range_utf16: Option<Range<usize>>,
23913        text: &str,
23914        new_selected_range_utf16: Option<Range<usize>>,
23915        window: &mut Window,
23916        cx: &mut Context<Self>,
23917    ) {
23918        if !self.input_enabled {
23919            return;
23920        }
23921
23922        let transaction = self.transact(window, cx, |this, window, cx| {
23923            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23924                let snapshot = this.buffer.read(cx).read(cx);
23925                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23926                    for marked_range in &mut marked_ranges {
23927                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23928                        marked_range.start.0 += relative_range_utf16.start;
23929                        marked_range.start =
23930                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23931                        marked_range.end =
23932                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23933                    }
23934                }
23935                Some(marked_ranges)
23936            } else if let Some(range_utf16) = range_utf16 {
23937                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23938                Some(this.selection_replacement_ranges(range_utf16, cx))
23939            } else {
23940                None
23941            };
23942
23943            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23944                let newest_selection_id = this.selections.newest_anchor().id;
23945                this.selections
23946                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23947                    .iter()
23948                    .zip(ranges_to_replace.iter())
23949                    .find_map(|(selection, range)| {
23950                        if selection.id == newest_selection_id {
23951                            Some(
23952                                (range.start.0 as isize - selection.head().0 as isize)
23953                                    ..(range.end.0 as isize - selection.head().0 as isize),
23954                            )
23955                        } else {
23956                            None
23957                        }
23958                    })
23959            });
23960
23961            cx.emit(EditorEvent::InputHandled {
23962                utf16_range_to_replace: range_to_replace,
23963                text: text.into(),
23964            });
23965
23966            if let Some(ranges) = ranges_to_replace {
23967                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23968                    s.select_ranges(ranges)
23969                });
23970            }
23971
23972            let marked_ranges = {
23973                let snapshot = this.buffer.read(cx).read(cx);
23974                this.selections
23975                    .disjoint_anchors_arc()
23976                    .iter()
23977                    .map(|selection| {
23978                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23979                    })
23980                    .collect::<Vec<_>>()
23981            };
23982
23983            if text.is_empty() {
23984                this.unmark_text(window, cx);
23985            } else {
23986                this.highlight_text::<InputComposition>(
23987                    marked_ranges.clone(),
23988                    HighlightStyle {
23989                        underline: Some(UnderlineStyle {
23990                            thickness: px(1.),
23991                            color: None,
23992                            wavy: false,
23993                        }),
23994                        ..Default::default()
23995                    },
23996                    cx,
23997                );
23998            }
23999
24000            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24001            let use_autoclose = this.use_autoclose;
24002            let use_auto_surround = this.use_auto_surround;
24003            this.set_use_autoclose(false);
24004            this.set_use_auto_surround(false);
24005            this.handle_input(text, window, cx);
24006            this.set_use_autoclose(use_autoclose);
24007            this.set_use_auto_surround(use_auto_surround);
24008
24009            if let Some(new_selected_range) = new_selected_range_utf16 {
24010                let snapshot = this.buffer.read(cx).read(cx);
24011                let new_selected_ranges = marked_ranges
24012                    .into_iter()
24013                    .map(|marked_range| {
24014                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24015                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24016                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24017                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24018                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24019                    })
24020                    .collect::<Vec<_>>();
24021
24022                drop(snapshot);
24023                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24024                    selections.select_ranges(new_selected_ranges)
24025                });
24026            }
24027        });
24028
24029        self.ime_transaction = self.ime_transaction.or(transaction);
24030        if let Some(transaction) = self.ime_transaction {
24031            self.buffer.update(cx, |buffer, cx| {
24032                buffer.group_until_transaction(transaction, cx);
24033            });
24034        }
24035
24036        if self.text_highlights::<InputComposition>(cx).is_none() {
24037            self.ime_transaction.take();
24038        }
24039    }
24040
24041    fn bounds_for_range(
24042        &mut self,
24043        range_utf16: Range<usize>,
24044        element_bounds: gpui::Bounds<Pixels>,
24045        window: &mut Window,
24046        cx: &mut Context<Self>,
24047    ) -> Option<gpui::Bounds<Pixels>> {
24048        let text_layout_details = self.text_layout_details(window);
24049        let CharacterDimensions {
24050            em_width,
24051            em_advance,
24052            line_height,
24053        } = self.character_dimensions(window);
24054
24055        let snapshot = self.snapshot(window, cx);
24056        let scroll_position = snapshot.scroll_position();
24057        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24058
24059        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24060        let x = Pixels::from(
24061            ScrollOffset::from(
24062                snapshot.x_for_display_point(start, &text_layout_details)
24063                    + self.gutter_dimensions.full_width(),
24064            ) - scroll_left,
24065        );
24066        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24067
24068        Some(Bounds {
24069            origin: element_bounds.origin + point(x, y),
24070            size: size(em_width, line_height),
24071        })
24072    }
24073
24074    fn character_index_for_point(
24075        &mut self,
24076        point: gpui::Point<Pixels>,
24077        _window: &mut Window,
24078        _cx: &mut Context<Self>,
24079    ) -> Option<usize> {
24080        let position_map = self.last_position_map.as_ref()?;
24081        if !position_map.text_hitbox.contains(&point) {
24082            return None;
24083        }
24084        let display_point = position_map.point_for_position(point).previous_valid;
24085        let anchor = position_map
24086            .snapshot
24087            .display_point_to_anchor(display_point, Bias::Left);
24088        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24089        Some(utf16_offset.0)
24090    }
24091}
24092
24093trait SelectionExt {
24094    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24095    fn spanned_rows(
24096        &self,
24097        include_end_if_at_line_start: bool,
24098        map: &DisplaySnapshot,
24099    ) -> Range<MultiBufferRow>;
24100}
24101
24102impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24103    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24104        let start = self
24105            .start
24106            .to_point(map.buffer_snapshot())
24107            .to_display_point(map);
24108        let end = self
24109            .end
24110            .to_point(map.buffer_snapshot())
24111            .to_display_point(map);
24112        if self.reversed {
24113            end..start
24114        } else {
24115            start..end
24116        }
24117    }
24118
24119    fn spanned_rows(
24120        &self,
24121        include_end_if_at_line_start: bool,
24122        map: &DisplaySnapshot,
24123    ) -> Range<MultiBufferRow> {
24124        let start = self.start.to_point(map.buffer_snapshot());
24125        let mut end = self.end.to_point(map.buffer_snapshot());
24126        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24127            end.row -= 1;
24128        }
24129
24130        let buffer_start = map.prev_line_boundary(start).0;
24131        let buffer_end = map.next_line_boundary(end).0;
24132        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24133    }
24134}
24135
24136impl<T: InvalidationRegion> InvalidationStack<T> {
24137    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24138    where
24139        S: Clone + ToOffset,
24140    {
24141        while let Some(region) = self.last() {
24142            let all_selections_inside_invalidation_ranges =
24143                if selections.len() == region.ranges().len() {
24144                    selections
24145                        .iter()
24146                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24147                        .all(|(selection, invalidation_range)| {
24148                            let head = selection.head().to_offset(buffer);
24149                            invalidation_range.start <= head && invalidation_range.end >= head
24150                        })
24151                } else {
24152                    false
24153                };
24154
24155            if all_selections_inside_invalidation_ranges {
24156                break;
24157            } else {
24158                self.pop();
24159            }
24160        }
24161    }
24162}
24163
24164impl<T> Default for InvalidationStack<T> {
24165    fn default() -> Self {
24166        Self(Default::default())
24167    }
24168}
24169
24170impl<T> Deref for InvalidationStack<T> {
24171    type Target = Vec<T>;
24172
24173    fn deref(&self) -> &Self::Target {
24174        &self.0
24175    }
24176}
24177
24178impl<T> DerefMut for InvalidationStack<T> {
24179    fn deref_mut(&mut self) -> &mut Self::Target {
24180        &mut self.0
24181    }
24182}
24183
24184impl InvalidationRegion for SnippetState {
24185    fn ranges(&self) -> &[Range<Anchor>] {
24186        &self.ranges[self.active_index]
24187    }
24188}
24189
24190fn edit_prediction_edit_text(
24191    current_snapshot: &BufferSnapshot,
24192    edits: &[(Range<Anchor>, String)],
24193    edit_preview: &EditPreview,
24194    include_deletions: bool,
24195    cx: &App,
24196) -> HighlightedText {
24197    let edits = edits
24198        .iter()
24199        .map(|(anchor, text)| {
24200            (
24201                anchor.start.text_anchor..anchor.end.text_anchor,
24202                text.clone(),
24203            )
24204        })
24205        .collect::<Vec<_>>();
24206
24207    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24208}
24209
24210fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24211    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24212    // Just show the raw edit text with basic styling
24213    let mut text = String::new();
24214    let mut highlights = Vec::new();
24215
24216    let insertion_highlight_style = HighlightStyle {
24217        color: Some(cx.theme().colors().text),
24218        ..Default::default()
24219    };
24220
24221    for (_, edit_text) in edits {
24222        let start_offset = text.len();
24223        text.push_str(edit_text);
24224        let end_offset = text.len();
24225
24226        if start_offset < end_offset {
24227            highlights.push((start_offset..end_offset, insertion_highlight_style));
24228        }
24229    }
24230
24231    HighlightedText {
24232        text: text.into(),
24233        highlights,
24234    }
24235}
24236
24237pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24238    match severity {
24239        lsp::DiagnosticSeverity::ERROR => colors.error,
24240        lsp::DiagnosticSeverity::WARNING => colors.warning,
24241        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24242        lsp::DiagnosticSeverity::HINT => colors.info,
24243        _ => colors.ignored,
24244    }
24245}
24246
24247pub fn styled_runs_for_code_label<'a>(
24248    label: &'a CodeLabel,
24249    syntax_theme: &'a theme::SyntaxTheme,
24250) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24251    let fade_out = HighlightStyle {
24252        fade_out: Some(0.35),
24253        ..Default::default()
24254    };
24255
24256    let mut prev_end = label.filter_range.end;
24257    label
24258        .runs
24259        .iter()
24260        .enumerate()
24261        .flat_map(move |(ix, (range, highlight_id))| {
24262            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24263                style
24264            } else {
24265                return Default::default();
24266            };
24267            let muted_style = style.highlight(fade_out);
24268
24269            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24270            if range.start >= label.filter_range.end {
24271                if range.start > prev_end {
24272                    runs.push((prev_end..range.start, fade_out));
24273                }
24274                runs.push((range.clone(), muted_style));
24275            } else if range.end <= label.filter_range.end {
24276                runs.push((range.clone(), style));
24277            } else {
24278                runs.push((range.start..label.filter_range.end, style));
24279                runs.push((label.filter_range.end..range.end, muted_style));
24280            }
24281            prev_end = cmp::max(prev_end, range.end);
24282
24283            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24284                runs.push((prev_end..label.text.len(), fade_out));
24285            }
24286
24287            runs
24288        })
24289}
24290
24291pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24292    let mut prev_index = 0;
24293    let mut prev_codepoint: Option<char> = None;
24294    text.char_indices()
24295        .chain([(text.len(), '\0')])
24296        .filter_map(move |(index, codepoint)| {
24297            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24298            let is_boundary = index == text.len()
24299                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24300                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24301            if is_boundary {
24302                let chunk = &text[prev_index..index];
24303                prev_index = index;
24304                Some(chunk)
24305            } else {
24306                None
24307            }
24308        })
24309}
24310
24311pub trait RangeToAnchorExt: Sized {
24312    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24313
24314    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24315        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24316        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24317    }
24318}
24319
24320impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24321    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24322        let start_offset = self.start.to_offset(snapshot);
24323        let end_offset = self.end.to_offset(snapshot);
24324        if start_offset == end_offset {
24325            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24326        } else {
24327            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24328        }
24329    }
24330}
24331
24332pub trait RowExt {
24333    fn as_f64(&self) -> f64;
24334
24335    fn next_row(&self) -> Self;
24336
24337    fn previous_row(&self) -> Self;
24338
24339    fn minus(&self, other: Self) -> u32;
24340}
24341
24342impl RowExt for DisplayRow {
24343    fn as_f64(&self) -> f64 {
24344        self.0 as _
24345    }
24346
24347    fn next_row(&self) -> Self {
24348        Self(self.0 + 1)
24349    }
24350
24351    fn previous_row(&self) -> Self {
24352        Self(self.0.saturating_sub(1))
24353    }
24354
24355    fn minus(&self, other: Self) -> u32 {
24356        self.0 - other.0
24357    }
24358}
24359
24360impl RowExt for MultiBufferRow {
24361    fn as_f64(&self) -> f64 {
24362        self.0 as _
24363    }
24364
24365    fn next_row(&self) -> Self {
24366        Self(self.0 + 1)
24367    }
24368
24369    fn previous_row(&self) -> Self {
24370        Self(self.0.saturating_sub(1))
24371    }
24372
24373    fn minus(&self, other: Self) -> u32 {
24374        self.0 - other.0
24375    }
24376}
24377
24378trait RowRangeExt {
24379    type Row;
24380
24381    fn len(&self) -> usize;
24382
24383    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24384}
24385
24386impl RowRangeExt for Range<MultiBufferRow> {
24387    type Row = MultiBufferRow;
24388
24389    fn len(&self) -> usize {
24390        (self.end.0 - self.start.0) as usize
24391    }
24392
24393    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24394        (self.start.0..self.end.0).map(MultiBufferRow)
24395    }
24396}
24397
24398impl RowRangeExt for Range<DisplayRow> {
24399    type Row = DisplayRow;
24400
24401    fn len(&self) -> usize {
24402        (self.end.0 - self.start.0) as usize
24403    }
24404
24405    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24406        (self.start.0..self.end.0).map(DisplayRow)
24407    }
24408}
24409
24410/// If select range has more than one line, we
24411/// just point the cursor to range.start.
24412fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24413    if range.start.row == range.end.row {
24414        range
24415    } else {
24416        range.start..range.start
24417    }
24418}
24419pub struct KillRing(ClipboardItem);
24420impl Global for KillRing {}
24421
24422const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24423
24424enum BreakpointPromptEditAction {
24425    Log,
24426    Condition,
24427    HitCondition,
24428}
24429
24430struct BreakpointPromptEditor {
24431    pub(crate) prompt: Entity<Editor>,
24432    editor: WeakEntity<Editor>,
24433    breakpoint_anchor: Anchor,
24434    breakpoint: Breakpoint,
24435    edit_action: BreakpointPromptEditAction,
24436    block_ids: HashSet<CustomBlockId>,
24437    editor_margins: Arc<Mutex<EditorMargins>>,
24438    _subscriptions: Vec<Subscription>,
24439}
24440
24441impl BreakpointPromptEditor {
24442    const MAX_LINES: u8 = 4;
24443
24444    fn new(
24445        editor: WeakEntity<Editor>,
24446        breakpoint_anchor: Anchor,
24447        breakpoint: Breakpoint,
24448        edit_action: BreakpointPromptEditAction,
24449        window: &mut Window,
24450        cx: &mut Context<Self>,
24451    ) -> Self {
24452        let base_text = match edit_action {
24453            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24454            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24455            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24456        }
24457        .map(|msg| msg.to_string())
24458        .unwrap_or_default();
24459
24460        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24461        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24462
24463        let prompt = cx.new(|cx| {
24464            let mut prompt = Editor::new(
24465                EditorMode::AutoHeight {
24466                    min_lines: 1,
24467                    max_lines: Some(Self::MAX_LINES as usize),
24468                },
24469                buffer,
24470                None,
24471                window,
24472                cx,
24473            );
24474            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24475            prompt.set_show_cursor_when_unfocused(false, cx);
24476            prompt.set_placeholder_text(
24477                match edit_action {
24478                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24479                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24480                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24481                },
24482                window,
24483                cx,
24484            );
24485
24486            prompt
24487        });
24488
24489        Self {
24490            prompt,
24491            editor,
24492            breakpoint_anchor,
24493            breakpoint,
24494            edit_action,
24495            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24496            block_ids: Default::default(),
24497            _subscriptions: vec![],
24498        }
24499    }
24500
24501    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24502        self.block_ids.extend(block_ids)
24503    }
24504
24505    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24506        if let Some(editor) = self.editor.upgrade() {
24507            let message = self
24508                .prompt
24509                .read(cx)
24510                .buffer
24511                .read(cx)
24512                .as_singleton()
24513                .expect("A multi buffer in breakpoint prompt isn't possible")
24514                .read(cx)
24515                .as_rope()
24516                .to_string();
24517
24518            editor.update(cx, |editor, cx| {
24519                editor.edit_breakpoint_at_anchor(
24520                    self.breakpoint_anchor,
24521                    self.breakpoint.clone(),
24522                    match self.edit_action {
24523                        BreakpointPromptEditAction::Log => {
24524                            BreakpointEditAction::EditLogMessage(message.into())
24525                        }
24526                        BreakpointPromptEditAction::Condition => {
24527                            BreakpointEditAction::EditCondition(message.into())
24528                        }
24529                        BreakpointPromptEditAction::HitCondition => {
24530                            BreakpointEditAction::EditHitCondition(message.into())
24531                        }
24532                    },
24533                    cx,
24534                );
24535
24536                editor.remove_blocks(self.block_ids.clone(), None, cx);
24537                cx.focus_self(window);
24538            });
24539        }
24540    }
24541
24542    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24543        self.editor
24544            .update(cx, |editor, cx| {
24545                editor.remove_blocks(self.block_ids.clone(), None, cx);
24546                window.focus(&editor.focus_handle);
24547            })
24548            .log_err();
24549    }
24550
24551    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24552        let settings = ThemeSettings::get_global(cx);
24553        let text_style = TextStyle {
24554            color: if self.prompt.read(cx).read_only(cx) {
24555                cx.theme().colors().text_disabled
24556            } else {
24557                cx.theme().colors().text
24558            },
24559            font_family: settings.buffer_font.family.clone(),
24560            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24561            font_size: settings.buffer_font_size(cx).into(),
24562            font_weight: settings.buffer_font.weight,
24563            line_height: relative(settings.buffer_line_height.value()),
24564            ..Default::default()
24565        };
24566        EditorElement::new(
24567            &self.prompt,
24568            EditorStyle {
24569                background: cx.theme().colors().editor_background,
24570                local_player: cx.theme().players().local(),
24571                text: text_style,
24572                ..Default::default()
24573            },
24574        )
24575    }
24576}
24577
24578impl Render for BreakpointPromptEditor {
24579    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24580        let editor_margins = *self.editor_margins.lock();
24581        let gutter_dimensions = editor_margins.gutter;
24582        h_flex()
24583            .key_context("Editor")
24584            .bg(cx.theme().colors().editor_background)
24585            .border_y_1()
24586            .border_color(cx.theme().status().info_border)
24587            .size_full()
24588            .py(window.line_height() / 2.5)
24589            .on_action(cx.listener(Self::confirm))
24590            .on_action(cx.listener(Self::cancel))
24591            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24592            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24593    }
24594}
24595
24596impl Focusable for BreakpointPromptEditor {
24597    fn focus_handle(&self, cx: &App) -> FocusHandle {
24598        self.prompt.focus_handle(cx)
24599    }
24600}
24601
24602fn all_edits_insertions_or_deletions(
24603    edits: &Vec<(Range<Anchor>, String)>,
24604    snapshot: &MultiBufferSnapshot,
24605) -> bool {
24606    let mut all_insertions = true;
24607    let mut all_deletions = true;
24608
24609    for (range, new_text) in edits.iter() {
24610        let range_is_empty = range.to_offset(snapshot).is_empty();
24611        let text_is_empty = new_text.is_empty();
24612
24613        if range_is_empty != text_is_empty {
24614            if range_is_empty {
24615                all_deletions = false;
24616            } else {
24617                all_insertions = false;
24618            }
24619        } else {
24620            return false;
24621        }
24622
24623        if !all_insertions && !all_deletions {
24624            return false;
24625        }
24626    }
24627    all_insertions || all_deletions
24628}
24629
24630struct MissingEditPredictionKeybindingTooltip;
24631
24632impl Render for MissingEditPredictionKeybindingTooltip {
24633    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24634        ui::tooltip_container(cx, |container, cx| {
24635            container
24636                .flex_shrink_0()
24637                .max_w_80()
24638                .min_h(rems_from_px(124.))
24639                .justify_between()
24640                .child(
24641                    v_flex()
24642                        .flex_1()
24643                        .text_ui_sm(cx)
24644                        .child(Label::new("Conflict with Accept Keybinding"))
24645                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24646                )
24647                .child(
24648                    h_flex()
24649                        .pb_1()
24650                        .gap_1()
24651                        .items_end()
24652                        .w_full()
24653                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24654                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24655                        }))
24656                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24657                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24658                        })),
24659                )
24660        })
24661    }
24662}
24663
24664#[derive(Debug, Clone, Copy, PartialEq)]
24665pub struct LineHighlight {
24666    pub background: Background,
24667    pub border: Option<gpui::Hsla>,
24668    pub include_gutter: bool,
24669    pub type_id: Option<TypeId>,
24670}
24671
24672struct LineManipulationResult {
24673    pub new_text: String,
24674    pub line_count_before: usize,
24675    pub line_count_after: usize,
24676}
24677
24678fn render_diff_hunk_controls(
24679    row: u32,
24680    status: &DiffHunkStatus,
24681    hunk_range: Range<Anchor>,
24682    is_created_file: bool,
24683    line_height: Pixels,
24684    editor: &Entity<Editor>,
24685    _window: &mut Window,
24686    cx: &mut App,
24687) -> AnyElement {
24688    h_flex()
24689        .h(line_height)
24690        .mr_1()
24691        .gap_1()
24692        .px_0p5()
24693        .pb_1()
24694        .border_x_1()
24695        .border_b_1()
24696        .border_color(cx.theme().colors().border_variant)
24697        .rounded_b_lg()
24698        .bg(cx.theme().colors().editor_background)
24699        .gap_1()
24700        .block_mouse_except_scroll()
24701        .shadow_md()
24702        .child(if status.has_secondary_hunk() {
24703            Button::new(("stage", row as u64), "Stage")
24704                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24705                .tooltip({
24706                    let focus_handle = editor.focus_handle(cx);
24707                    move |_window, cx| {
24708                        Tooltip::for_action_in(
24709                            "Stage Hunk",
24710                            &::git::ToggleStaged,
24711                            &focus_handle,
24712                            cx,
24713                        )
24714                    }
24715                })
24716                .on_click({
24717                    let editor = editor.clone();
24718                    move |_event, _window, cx| {
24719                        editor.update(cx, |editor, cx| {
24720                            editor.stage_or_unstage_diff_hunks(
24721                                true,
24722                                vec![hunk_range.start..hunk_range.start],
24723                                cx,
24724                            );
24725                        });
24726                    }
24727                })
24728        } else {
24729            Button::new(("unstage", row as u64), "Unstage")
24730                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24731                .tooltip({
24732                    let focus_handle = editor.focus_handle(cx);
24733                    move |_window, cx| {
24734                        Tooltip::for_action_in(
24735                            "Unstage Hunk",
24736                            &::git::ToggleStaged,
24737                            &focus_handle,
24738                            cx,
24739                        )
24740                    }
24741                })
24742                .on_click({
24743                    let editor = editor.clone();
24744                    move |_event, _window, cx| {
24745                        editor.update(cx, |editor, cx| {
24746                            editor.stage_or_unstage_diff_hunks(
24747                                false,
24748                                vec![hunk_range.start..hunk_range.start],
24749                                cx,
24750                            );
24751                        });
24752                    }
24753                })
24754        })
24755        .child(
24756            Button::new(("restore", row as u64), "Restore")
24757                .tooltip({
24758                    let focus_handle = editor.focus_handle(cx);
24759                    move |_window, cx| {
24760                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24761                    }
24762                })
24763                .on_click({
24764                    let editor = editor.clone();
24765                    move |_event, window, cx| {
24766                        editor.update(cx, |editor, cx| {
24767                            let snapshot = editor.snapshot(window, cx);
24768                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24769                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24770                        });
24771                    }
24772                })
24773                .disabled(is_created_file),
24774        )
24775        .when(
24776            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24777            |el| {
24778                el.child(
24779                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24780                        .shape(IconButtonShape::Square)
24781                        .icon_size(IconSize::Small)
24782                        // .disabled(!has_multiple_hunks)
24783                        .tooltip({
24784                            let focus_handle = editor.focus_handle(cx);
24785                            move |_window, cx| {
24786                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24787                            }
24788                        })
24789                        .on_click({
24790                            let editor = editor.clone();
24791                            move |_event, window, cx| {
24792                                editor.update(cx, |editor, cx| {
24793                                    let snapshot = editor.snapshot(window, cx);
24794                                    let position =
24795                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24796                                    editor.go_to_hunk_before_or_after_position(
24797                                        &snapshot,
24798                                        position,
24799                                        Direction::Next,
24800                                        window,
24801                                        cx,
24802                                    );
24803                                    editor.expand_selected_diff_hunks(cx);
24804                                });
24805                            }
24806                        }),
24807                )
24808                .child(
24809                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24810                        .shape(IconButtonShape::Square)
24811                        .icon_size(IconSize::Small)
24812                        // .disabled(!has_multiple_hunks)
24813                        .tooltip({
24814                            let focus_handle = editor.focus_handle(cx);
24815                            move |_window, cx| {
24816                                Tooltip::for_action_in(
24817                                    "Previous Hunk",
24818                                    &GoToPreviousHunk,
24819                                    &focus_handle,
24820                                    cx,
24821                                )
24822                            }
24823                        })
24824                        .on_click({
24825                            let editor = editor.clone();
24826                            move |_event, window, cx| {
24827                                editor.update(cx, |editor, cx| {
24828                                    let snapshot = editor.snapshot(window, cx);
24829                                    let point =
24830                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24831                                    editor.go_to_hunk_before_or_after_position(
24832                                        &snapshot,
24833                                        point,
24834                                        Direction::Prev,
24835                                        window,
24836                                        cx,
24837                                    );
24838                                    editor.expand_selected_diff_hunks(cx);
24839                                });
24840                            }
24841                        }),
24842                )
24843            },
24844        )
24845        .into_any_element()
24846}
24847
24848pub fn multibuffer_context_lines(cx: &App) -> u32 {
24849    EditorSettings::try_get(cx)
24850        .map(|settings| settings.excerpt_context_lines)
24851        .unwrap_or(2)
24852        .min(32)
24853}