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::{
  167    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  168    update_settings_file,
  169};
  170use smallvec::{SmallVec, smallvec};
  171use snippet::Snippet;
  172use std::{
  173    any::{Any, TypeId},
  174    borrow::Cow,
  175    cell::{OnceCell, RefCell},
  176    cmp::{self, Ordering, Reverse},
  177    iter::{self, Peekable},
  178    mem,
  179    num::NonZeroU32,
  180    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  181    path::{Path, PathBuf},
  182    rc::Rc,
  183    sync::Arc,
  184    time::{Duration, Instant},
  185};
  186use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  187use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  188use theme::{
  189    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  190    observe_buffer_font_size_adjustment,
  191};
  192use ui::{
  193    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  194    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  195};
  196use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  197use workspace::{
  198    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  199    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  200    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  201    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  202    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  203    searchable::SearchEvent,
  204};
  205
  206use crate::{
  207    code_context_menus::CompletionsMenuSource,
  208    editor_settings::MultiCursorModifier,
  209    hover_links::{find_url, find_url_from_range},
  210    inlays::{
  211        InlineValueCache,
  212        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  213    },
  214    scroll::{ScrollOffset, ScrollPixelOffset},
  215    selections_collection::resolve_selections_wrapping_blocks,
  216    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  217};
  218
  219pub const FILE_HEADER_HEIGHT: u32 = 2;
  220pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  221const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  222const MAX_LINE_LEN: usize = 1024;
  223const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  224const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  225pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  226#[doc(hidden)]
  227pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  228pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  229
  230pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  233pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  234
  235pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  236pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  237pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  238
  239pub type RenderDiffHunkControlsFn = Arc<
  240    dyn Fn(
  241        u32,
  242        &DiffHunkStatus,
  243        Range<Anchor>,
  244        bool,
  245        Pixels,
  246        &Entity<Editor>,
  247        &mut Window,
  248        &mut App,
  249    ) -> AnyElement,
  250>;
  251
  252enum ReportEditorEvent {
  253    Saved { auto_saved: bool },
  254    EditorOpened,
  255    Closed,
  256}
  257
  258impl ReportEditorEvent {
  259    pub fn event_type(&self) -> &'static str {
  260        match self {
  261            Self::Saved { .. } => "Editor Saved",
  262            Self::EditorOpened => "Editor Opened",
  263            Self::Closed => "Editor Closed",
  264        }
  265    }
  266}
  267
  268pub enum ActiveDebugLine {}
  269pub enum DebugStackFrameLine {}
  270enum DocumentHighlightRead {}
  271enum DocumentHighlightWrite {}
  272enum InputComposition {}
  273pub enum PendingInput {}
  274enum SelectedTextHighlight {}
  275
  276pub enum ConflictsOuter {}
  277pub enum ConflictsOurs {}
  278pub enum ConflictsTheirs {}
  279pub enum ConflictsOursMarker {}
  280pub enum ConflictsTheirsMarker {}
  281
  282#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  283pub enum Navigated {
  284    Yes,
  285    No,
  286}
  287
  288impl Navigated {
  289    pub fn from_bool(yes: bool) -> Navigated {
  290        if yes { Navigated::Yes } else { Navigated::No }
  291    }
  292}
  293
  294#[derive(Debug, Clone, PartialEq, Eq)]
  295enum DisplayDiffHunk {
  296    Folded {
  297        display_row: DisplayRow,
  298    },
  299    Unfolded {
  300        is_created_file: bool,
  301        diff_base_byte_range: Range<usize>,
  302        display_row_range: Range<DisplayRow>,
  303        multi_buffer_range: Range<Anchor>,
  304        status: DiffHunkStatus,
  305    },
  306}
  307
  308pub enum HideMouseCursorOrigin {
  309    TypingAction,
  310    MovementAction,
  311}
  312
  313pub fn init_settings(cx: &mut App) {
  314    EditorSettings::register(cx);
  315}
  316
  317pub fn init(cx: &mut App) {
  318    init_settings(cx);
  319
  320    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  321
  322    workspace::register_project_item::<Editor>(cx);
  323    workspace::FollowableViewRegistry::register::<Editor>(cx);
  324    workspace::register_serializable_item::<Editor>(cx);
  325
  326    cx.observe_new(
  327        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  328            workspace.register_action(Editor::new_file);
  329            workspace.register_action(Editor::new_file_split);
  330            workspace.register_action(Editor::new_file_vertical);
  331            workspace.register_action(Editor::new_file_horizontal);
  332            workspace.register_action(Editor::cancel_language_server_work);
  333            workspace.register_action(Editor::toggle_focus);
  334        },
  335    )
  336    .detach();
  337
  338    cx.on_action(move |_: &workspace::NewFile, cx| {
  339        let app_state = workspace::AppState::global(cx);
  340        if let Some(app_state) = app_state.upgrade() {
  341            workspace::open_new(
  342                Default::default(),
  343                app_state,
  344                cx,
  345                |workspace, window, cx| {
  346                    Editor::new_file(workspace, &Default::default(), window, cx)
  347                },
  348            )
  349            .detach();
  350        }
  351    });
  352    cx.on_action(move |_: &workspace::NewWindow, cx| {
  353        let app_state = workspace::AppState::global(cx);
  354        if let Some(app_state) = app_state.upgrade() {
  355            workspace::open_new(
  356                Default::default(),
  357                app_state,
  358                cx,
  359                |workspace, window, cx| {
  360                    cx.activate(true);
  361                    Editor::new_file(workspace, &Default::default(), window, cx)
  362                },
  363            )
  364            .detach();
  365        }
  366    });
  367}
  368
  369pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  370    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  371}
  372
  373pub trait DiagnosticRenderer {
  374    fn render_group(
  375        &self,
  376        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  377        buffer_id: BufferId,
  378        snapshot: EditorSnapshot,
  379        editor: WeakEntity<Editor>,
  380        cx: &mut App,
  381    ) -> Vec<BlockProperties<Anchor>>;
  382
  383    fn render_hover(
  384        &self,
  385        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  386        range: Range<Point>,
  387        buffer_id: BufferId,
  388        cx: &mut App,
  389    ) -> Option<Entity<markdown::Markdown>>;
  390
  391    fn open_link(
  392        &self,
  393        editor: &mut Editor,
  394        link: SharedString,
  395        window: &mut Window,
  396        cx: &mut Context<Editor>,
  397    );
  398}
  399
  400pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  401
  402impl GlobalDiagnosticRenderer {
  403    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  404        cx.try_global::<Self>().map(|g| g.0.clone())
  405    }
  406}
  407
  408impl gpui::Global for GlobalDiagnosticRenderer {}
  409pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  410    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  411}
  412
  413pub struct SearchWithinRange;
  414
  415trait InvalidationRegion {
  416    fn ranges(&self) -> &[Range<Anchor>];
  417}
  418
  419#[derive(Clone, Debug, PartialEq)]
  420pub enum SelectPhase {
  421    Begin {
  422        position: DisplayPoint,
  423        add: bool,
  424        click_count: usize,
  425    },
  426    BeginColumnar {
  427        position: DisplayPoint,
  428        reset: bool,
  429        mode: ColumnarMode,
  430        goal_column: u32,
  431    },
  432    Extend {
  433        position: DisplayPoint,
  434        click_count: usize,
  435    },
  436    Update {
  437        position: DisplayPoint,
  438        goal_column: u32,
  439        scroll_delta: gpui::Point<f32>,
  440    },
  441    End,
  442}
  443
  444#[derive(Clone, Debug, PartialEq)]
  445pub enum ColumnarMode {
  446    FromMouse,
  447    FromSelection,
  448}
  449
  450#[derive(Clone, Debug)]
  451pub enum SelectMode {
  452    Character,
  453    Word(Range<Anchor>),
  454    Line(Range<Anchor>),
  455    All,
  456}
  457
  458#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  459pub enum SizingBehavior {
  460    /// The editor will layout itself using `size_full` and will include the vertical
  461    /// scroll margin as requested by user settings.
  462    #[default]
  463    Default,
  464    /// The editor will layout itself using `size_full`, but will not have any
  465    /// vertical overscroll.
  466    ExcludeOverscrollMargin,
  467    /// The editor will request a vertical size according to its content and will be
  468    /// layouted without a vertical scroll margin.
  469    SizeByContent,
  470}
  471
  472#[derive(Clone, PartialEq, Eq, Debug)]
  473pub enum EditorMode {
  474    SingleLine,
  475    AutoHeight {
  476        min_lines: usize,
  477        max_lines: Option<usize>,
  478    },
  479    Full {
  480        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  481        scale_ui_elements_with_buffer_font_size: bool,
  482        /// When set to `true`, the editor will render a background for the active line.
  483        show_active_line_background: bool,
  484        /// Determines the sizing behavior for this editor
  485        sizing_behavior: SizingBehavior,
  486    },
  487    Minimap {
  488        parent: WeakEntity<Editor>,
  489    },
  490}
  491
  492impl EditorMode {
  493    pub fn full() -> Self {
  494        Self::Full {
  495            scale_ui_elements_with_buffer_font_size: true,
  496            show_active_line_background: true,
  497            sizing_behavior: SizingBehavior::Default,
  498        }
  499    }
  500
  501    #[inline]
  502    pub fn is_full(&self) -> bool {
  503        matches!(self, Self::Full { .. })
  504    }
  505
  506    #[inline]
  507    pub fn is_single_line(&self) -> bool {
  508        matches!(self, Self::SingleLine { .. })
  509    }
  510
  511    #[inline]
  512    fn is_minimap(&self) -> bool {
  513        matches!(self, Self::Minimap { .. })
  514    }
  515}
  516
  517#[derive(Copy, Clone, Debug)]
  518pub enum SoftWrap {
  519    /// Prefer not to wrap at all.
  520    ///
  521    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  522    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  523    GitDiff,
  524    /// Prefer a single line generally, unless an overly long line is encountered.
  525    None,
  526    /// Soft wrap lines that exceed the editor width.
  527    EditorWidth,
  528    /// Soft wrap lines at the preferred line length.
  529    Column(u32),
  530    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  531    Bounded(u32),
  532}
  533
  534#[derive(Clone)]
  535pub struct EditorStyle {
  536    pub background: Hsla,
  537    pub border: Hsla,
  538    pub local_player: PlayerColor,
  539    pub text: TextStyle,
  540    pub scrollbar_width: Pixels,
  541    pub syntax: Arc<SyntaxTheme>,
  542    pub status: StatusColors,
  543    pub inlay_hints_style: HighlightStyle,
  544    pub edit_prediction_styles: EditPredictionStyles,
  545    pub unnecessary_code_fade: f32,
  546    pub show_underlines: bool,
  547}
  548
  549impl Default for EditorStyle {
  550    fn default() -> Self {
  551        Self {
  552            background: Hsla::default(),
  553            border: Hsla::default(),
  554            local_player: PlayerColor::default(),
  555            text: TextStyle::default(),
  556            scrollbar_width: Pixels::default(),
  557            syntax: Default::default(),
  558            // HACK: Status colors don't have a real default.
  559            // We should look into removing the status colors from the editor
  560            // style and retrieve them directly from the theme.
  561            status: StatusColors::dark(),
  562            inlay_hints_style: HighlightStyle::default(),
  563            edit_prediction_styles: EditPredictionStyles {
  564                insertion: HighlightStyle::default(),
  565                whitespace: HighlightStyle::default(),
  566            },
  567            unnecessary_code_fade: Default::default(),
  568            show_underlines: true,
  569        }
  570    }
  571}
  572
  573pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  574    let show_background = language_settings::language_settings(None, None, cx)
  575        .inlay_hints
  576        .show_background;
  577
  578    let mut style = cx.theme().syntax().get("hint");
  579
  580    if style.color.is_none() {
  581        style.color = Some(cx.theme().status().hint);
  582    }
  583
  584    if !show_background {
  585        style.background_color = None;
  586        return style;
  587    }
  588
  589    if style.background_color.is_none() {
  590        style.background_color = Some(cx.theme().status().hint_background);
  591    }
  592
  593    style
  594}
  595
  596pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  597    EditPredictionStyles {
  598        insertion: HighlightStyle {
  599            color: Some(cx.theme().status().predictive),
  600            ..HighlightStyle::default()
  601        },
  602        whitespace: HighlightStyle {
  603            background_color: Some(cx.theme().status().created_background),
  604            ..HighlightStyle::default()
  605        },
  606    }
  607}
  608
  609type CompletionId = usize;
  610
  611pub(crate) enum EditDisplayMode {
  612    TabAccept,
  613    DiffPopover,
  614    Inline,
  615}
  616
  617enum EditPrediction {
  618    Edit {
  619        edits: Vec<(Range<Anchor>, String)>,
  620        edit_preview: Option<EditPreview>,
  621        display_mode: EditDisplayMode,
  622        snapshot: BufferSnapshot,
  623    },
  624    /// Move to a specific location in the active editor
  625    MoveWithin {
  626        target: Anchor,
  627        snapshot: BufferSnapshot,
  628    },
  629    /// Move to a specific location in a different editor (not the active one)
  630    MoveOutside {
  631        target: language::Anchor,
  632        snapshot: BufferSnapshot,
  633    },
  634}
  635
  636struct EditPredictionState {
  637    inlay_ids: Vec<InlayId>,
  638    completion: EditPrediction,
  639    completion_id: Option<SharedString>,
  640    invalidation_range: Option<Range<Anchor>>,
  641}
  642
  643enum EditPredictionSettings {
  644    Disabled,
  645    Enabled {
  646        show_in_menu: bool,
  647        preview_requires_modifier: bool,
  648    },
  649}
  650
  651enum EditPredictionHighlight {}
  652
  653#[derive(Debug, Clone)]
  654struct InlineDiagnostic {
  655    message: SharedString,
  656    group_id: usize,
  657    is_primary: bool,
  658    start: Point,
  659    severity: lsp::DiagnosticSeverity,
  660}
  661
  662pub enum MenuEditPredictionsPolicy {
  663    Never,
  664    ByProvider,
  665}
  666
  667pub enum EditPredictionPreview {
  668    /// Modifier is not pressed
  669    Inactive { released_too_fast: bool },
  670    /// Modifier pressed
  671    Active {
  672        since: Instant,
  673        previous_scroll_position: Option<ScrollAnchor>,
  674    },
  675}
  676
  677impl EditPredictionPreview {
  678    pub fn released_too_fast(&self) -> bool {
  679        match self {
  680            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  681            EditPredictionPreview::Active { .. } => false,
  682        }
  683    }
  684
  685    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  686        if let EditPredictionPreview::Active {
  687            previous_scroll_position,
  688            ..
  689        } = self
  690        {
  691            *previous_scroll_position = scroll_position;
  692        }
  693    }
  694}
  695
  696pub struct ContextMenuOptions {
  697    pub min_entries_visible: usize,
  698    pub max_entries_visible: usize,
  699    pub placement: Option<ContextMenuPlacement>,
  700}
  701
  702#[derive(Debug, Clone, PartialEq, Eq)]
  703pub enum ContextMenuPlacement {
  704    Above,
  705    Below,
  706}
  707
  708#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  709struct EditorActionId(usize);
  710
  711impl EditorActionId {
  712    pub fn post_inc(&mut self) -> Self {
  713        let answer = self.0;
  714
  715        *self = Self(answer + 1);
  716
  717        Self(answer)
  718    }
  719}
  720
  721// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  722// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  723
  724type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  725type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  726
  727#[derive(Default)]
  728struct ScrollbarMarkerState {
  729    scrollbar_size: Size<Pixels>,
  730    dirty: bool,
  731    markers: Arc<[PaintQuad]>,
  732    pending_refresh: Option<Task<Result<()>>>,
  733}
  734
  735impl ScrollbarMarkerState {
  736    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  737        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  738    }
  739}
  740
  741#[derive(Clone, Copy, PartialEq, Eq)]
  742pub enum MinimapVisibility {
  743    Disabled,
  744    Enabled {
  745        /// The configuration currently present in the users settings.
  746        setting_configuration: bool,
  747        /// Whether to override the currently set visibility from the users setting.
  748        toggle_override: bool,
  749    },
  750}
  751
  752impl MinimapVisibility {
  753    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  754        if mode.is_full() {
  755            Self::Enabled {
  756                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  757                toggle_override: false,
  758            }
  759        } else {
  760            Self::Disabled
  761        }
  762    }
  763
  764    fn hidden(&self) -> Self {
  765        match *self {
  766            Self::Enabled {
  767                setting_configuration,
  768                ..
  769            } => Self::Enabled {
  770                setting_configuration,
  771                toggle_override: setting_configuration,
  772            },
  773            Self::Disabled => Self::Disabled,
  774        }
  775    }
  776
  777    fn disabled(&self) -> bool {
  778        matches!(*self, Self::Disabled)
  779    }
  780
  781    fn settings_visibility(&self) -> bool {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                ..
  786            } => setting_configuration,
  787            _ => false,
  788        }
  789    }
  790
  791    fn visible(&self) -> bool {
  792        match *self {
  793            Self::Enabled {
  794                setting_configuration,
  795                toggle_override,
  796            } => setting_configuration ^ toggle_override,
  797            _ => false,
  798        }
  799    }
  800
  801    fn toggle_visibility(&self) -> Self {
  802        match *self {
  803            Self::Enabled {
  804                toggle_override,
  805                setting_configuration,
  806            } => Self::Enabled {
  807                setting_configuration,
  808                toggle_override: !toggle_override,
  809            },
  810            Self::Disabled => Self::Disabled,
  811        }
  812    }
  813}
  814
  815#[derive(Clone, Debug)]
  816struct RunnableTasks {
  817    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  818    offset: multi_buffer::Anchor,
  819    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  820    column: u32,
  821    // Values of all named captures, including those starting with '_'
  822    extra_variables: HashMap<String, String>,
  823    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  824    context_range: Range<BufferOffset>,
  825}
  826
  827impl RunnableTasks {
  828    fn resolve<'a>(
  829        &'a self,
  830        cx: &'a task::TaskContext,
  831    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  832        self.templates.iter().filter_map(|(kind, template)| {
  833            template
  834                .resolve_task(&kind.to_id_base(), cx)
  835                .map(|task| (kind.clone(), task))
  836        })
  837    }
  838}
  839
  840#[derive(Clone)]
  841pub struct ResolvedTasks {
  842    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  843    position: Anchor,
  844}
  845
  846#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  847struct BufferOffset(usize);
  848
  849/// Addons allow storing per-editor state in other crates (e.g. Vim)
  850pub trait Addon: 'static {
  851    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  852
  853    fn render_buffer_header_controls(
  854        &self,
  855        _: &ExcerptInfo,
  856        _: &Window,
  857        _: &App,
  858    ) -> Option<AnyElement> {
  859        None
  860    }
  861
  862    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  863        None
  864    }
  865
  866    fn to_any(&self) -> &dyn std::any::Any;
  867
  868    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  869        None
  870    }
  871}
  872
  873struct ChangeLocation {
  874    current: Option<Vec<Anchor>>,
  875    original: Vec<Anchor>,
  876}
  877impl ChangeLocation {
  878    fn locations(&self) -> &[Anchor] {
  879        self.current.as_ref().unwrap_or(&self.original)
  880    }
  881}
  882
  883/// A set of caret positions, registered when the editor was edited.
  884pub struct ChangeList {
  885    changes: Vec<ChangeLocation>,
  886    /// Currently "selected" change.
  887    position: Option<usize>,
  888}
  889
  890impl ChangeList {
  891    pub fn new() -> Self {
  892        Self {
  893            changes: Vec::new(),
  894            position: None,
  895        }
  896    }
  897
  898    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  899    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  900    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  901        if self.changes.is_empty() {
  902            return None;
  903        }
  904
  905        let prev = self.position.unwrap_or(self.changes.len());
  906        let next = if direction == Direction::Prev {
  907            prev.saturating_sub(count)
  908        } else {
  909            (prev + count).min(self.changes.len() - 1)
  910        };
  911        self.position = Some(next);
  912        self.changes.get(next).map(|change| change.locations())
  913    }
  914
  915    /// Adds a new change to the list, resetting the change list position.
  916    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  917        self.position.take();
  918        if let Some(last) = self.changes.last_mut()
  919            && group
  920        {
  921            last.current = Some(new_positions)
  922        } else {
  923            self.changes.push(ChangeLocation {
  924                original: new_positions,
  925                current: None,
  926            });
  927        }
  928    }
  929
  930    pub fn last(&self) -> Option<&[Anchor]> {
  931        self.changes.last().map(|change| change.locations())
  932    }
  933
  934    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  935        self.changes.last().map(|change| change.original.as_slice())
  936    }
  937
  938    pub fn invert_last_group(&mut self) {
  939        if let Some(last) = self.changes.last_mut()
  940            && let Some(current) = last.current.as_mut()
  941        {
  942            mem::swap(&mut last.original, current);
  943        }
  944    }
  945}
  946
  947#[derive(Clone)]
  948struct InlineBlamePopoverState {
  949    scroll_handle: ScrollHandle,
  950    commit_message: Option<ParsedCommitMessage>,
  951    markdown: Entity<Markdown>,
  952}
  953
  954struct InlineBlamePopover {
  955    position: gpui::Point<Pixels>,
  956    hide_task: Option<Task<()>>,
  957    popover_bounds: Option<Bounds<Pixels>>,
  958    popover_state: InlineBlamePopoverState,
  959    keyboard_grace: bool,
  960}
  961
  962enum SelectionDragState {
  963    /// State when no drag related activity is detected.
  964    None,
  965    /// State when the mouse is down on a selection that is about to be dragged.
  966    ReadyToDrag {
  967        selection: Selection<Anchor>,
  968        click_position: gpui::Point<Pixels>,
  969        mouse_down_time: Instant,
  970    },
  971    /// State when the mouse is dragging the selection in the editor.
  972    Dragging {
  973        selection: Selection<Anchor>,
  974        drop_cursor: Selection<Anchor>,
  975        hide_drop_cursor: bool,
  976    },
  977}
  978
  979enum ColumnarSelectionState {
  980    FromMouse {
  981        selection_tail: Anchor,
  982        display_point: Option<DisplayPoint>,
  983    },
  984    FromSelection {
  985        selection_tail: Anchor,
  986    },
  987}
  988
  989/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  990/// a breakpoint on them.
  991#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  992struct PhantomBreakpointIndicator {
  993    display_row: DisplayRow,
  994    /// There's a small debounce between hovering over the line and showing the indicator.
  995    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  996    is_active: bool,
  997    collides_with_existing_breakpoint: bool,
  998}
  999
 1000/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1001///
 1002/// See the [module level documentation](self) for more information.
 1003pub struct Editor {
 1004    focus_handle: FocusHandle,
 1005    last_focused_descendant: Option<WeakFocusHandle>,
 1006    /// The text buffer being edited
 1007    buffer: Entity<MultiBuffer>,
 1008    /// Map of how text in the buffer should be displayed.
 1009    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1010    pub display_map: Entity<DisplayMap>,
 1011    placeholder_display_map: Option<Entity<DisplayMap>>,
 1012    pub selections: SelectionsCollection,
 1013    pub scroll_manager: ScrollManager,
 1014    /// When inline assist editors are linked, they all render cursors because
 1015    /// typing enters text into each of them, even the ones that aren't focused.
 1016    pub(crate) show_cursor_when_unfocused: bool,
 1017    columnar_selection_state: Option<ColumnarSelectionState>,
 1018    add_selections_state: Option<AddSelectionsState>,
 1019    select_next_state: Option<SelectNextState>,
 1020    select_prev_state: Option<SelectNextState>,
 1021    selection_history: SelectionHistory,
 1022    defer_selection_effects: bool,
 1023    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1024    autoclose_regions: Vec<AutocloseRegion>,
 1025    snippet_stack: InvalidationStack<SnippetState>,
 1026    select_syntax_node_history: SelectSyntaxNodeHistory,
 1027    ime_transaction: Option<TransactionId>,
 1028    pub diagnostics_max_severity: DiagnosticSeverity,
 1029    active_diagnostics: ActiveDiagnostic,
 1030    show_inline_diagnostics: bool,
 1031    inline_diagnostics_update: Task<()>,
 1032    inline_diagnostics_enabled: bool,
 1033    diagnostics_enabled: bool,
 1034    word_completions_enabled: bool,
 1035    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1036    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1037    hard_wrap: Option<usize>,
 1038    project: Option<Entity<Project>>,
 1039    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1040    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1041    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1042    blink_manager: Entity<BlinkManager>,
 1043    show_cursor_names: bool,
 1044    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1045    pub show_local_selections: bool,
 1046    mode: EditorMode,
 1047    show_breadcrumbs: bool,
 1048    show_gutter: bool,
 1049    show_scrollbars: ScrollbarAxes,
 1050    minimap_visibility: MinimapVisibility,
 1051    offset_content: bool,
 1052    disable_expand_excerpt_buttons: bool,
 1053    show_line_numbers: Option<bool>,
 1054    use_relative_line_numbers: Option<bool>,
 1055    show_git_diff_gutter: Option<bool>,
 1056    show_code_actions: Option<bool>,
 1057    show_runnables: Option<bool>,
 1058    show_breakpoints: Option<bool>,
 1059    show_wrap_guides: Option<bool>,
 1060    show_indent_guides: Option<bool>,
 1061    highlight_order: usize,
 1062    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1063    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1064    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1065    scrollbar_marker_state: ScrollbarMarkerState,
 1066    active_indent_guides_state: ActiveIndentGuidesState,
 1067    nav_history: Option<ItemNavHistory>,
 1068    context_menu: RefCell<Option<CodeContextMenu>>,
 1069    context_menu_options: Option<ContextMenuOptions>,
 1070    mouse_context_menu: Option<MouseContextMenu>,
 1071    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1072    inline_blame_popover: Option<InlineBlamePopover>,
 1073    inline_blame_popover_show_task: Option<Task<()>>,
 1074    signature_help_state: SignatureHelpState,
 1075    auto_signature_help: Option<bool>,
 1076    find_all_references_task_sources: Vec<Anchor>,
 1077    next_completion_id: CompletionId,
 1078    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1079    code_actions_task: Option<Task<Result<()>>>,
 1080    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1081    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1082    document_highlights_task: Option<Task<()>>,
 1083    linked_editing_range_task: Option<Task<Option<()>>>,
 1084    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1085    pending_rename: Option<RenameState>,
 1086    searchable: bool,
 1087    cursor_shape: CursorShape,
 1088    current_line_highlight: Option<CurrentLineHighlight>,
 1089    autoindent_mode: Option<AutoindentMode>,
 1090    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1091    input_enabled: bool,
 1092    use_modal_editing: bool,
 1093    read_only: bool,
 1094    leader_id: Option<CollaboratorId>,
 1095    remote_id: Option<ViewId>,
 1096    pub hover_state: HoverState,
 1097    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1098    gutter_hovered: bool,
 1099    hovered_link_state: Option<HoveredLinkState>,
 1100    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1101    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1102    active_edit_prediction: Option<EditPredictionState>,
 1103    /// Used to prevent flickering as the user types while the menu is open
 1104    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1105    edit_prediction_settings: EditPredictionSettings,
 1106    edit_predictions_hidden_for_vim_mode: bool,
 1107    show_edit_predictions_override: Option<bool>,
 1108    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1109    edit_prediction_preview: EditPredictionPreview,
 1110    edit_prediction_indent_conflict: bool,
 1111    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1112    next_inlay_id: usize,
 1113    next_color_inlay_id: usize,
 1114    _subscriptions: Vec<Subscription>,
 1115    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1116    gutter_dimensions: GutterDimensions,
 1117    style: Option<EditorStyle>,
 1118    text_style_refinement: Option<TextStyleRefinement>,
 1119    next_editor_action_id: EditorActionId,
 1120    editor_actions: Rc<
 1121        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1122    >,
 1123    use_autoclose: bool,
 1124    use_auto_surround: bool,
 1125    auto_replace_emoji_shortcode: bool,
 1126    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1127    show_git_blame_gutter: bool,
 1128    show_git_blame_inline: bool,
 1129    show_git_blame_inline_delay_task: Option<Task<()>>,
 1130    git_blame_inline_enabled: bool,
 1131    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1132    serialize_dirty_buffers: bool,
 1133    show_selection_menu: Option<bool>,
 1134    blame: Option<Entity<GitBlame>>,
 1135    blame_subscription: Option<Subscription>,
 1136    custom_context_menu: Option<
 1137        Box<
 1138            dyn 'static
 1139                + Fn(
 1140                    &mut Self,
 1141                    DisplayPoint,
 1142                    &mut Window,
 1143                    &mut Context<Self>,
 1144                ) -> Option<Entity<ui::ContextMenu>>,
 1145        >,
 1146    >,
 1147    last_bounds: Option<Bounds<Pixels>>,
 1148    last_position_map: Option<Rc<PositionMap>>,
 1149    expect_bounds_change: Option<Bounds<Pixels>>,
 1150    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1151    tasks_update_task: Option<Task<()>>,
 1152    breakpoint_store: Option<Entity<BreakpointStore>>,
 1153    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1154    hovered_diff_hunk_row: Option<DisplayRow>,
 1155    pull_diagnostics_task: Task<()>,
 1156    in_project_search: bool,
 1157    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1158    breadcrumb_header: Option<String>,
 1159    focused_block: Option<FocusedBlock>,
 1160    next_scroll_position: NextScrollCursorCenterTopBottom,
 1161    addons: HashMap<TypeId, Box<dyn Addon>>,
 1162    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1163    load_diff_task: Option<Shared<Task<()>>>,
 1164    /// Whether we are temporarily displaying a diff other than git's
 1165    temporary_diff_override: bool,
 1166    selection_mark_mode: bool,
 1167    toggle_fold_multiple_buffers: Task<()>,
 1168    _scroll_cursor_center_top_bottom_task: Task<()>,
 1169    serialize_selections: Task<()>,
 1170    serialize_folds: Task<()>,
 1171    mouse_cursor_hidden: bool,
 1172    minimap: Option<Entity<Self>>,
 1173    hide_mouse_mode: HideMouseMode,
 1174    pub change_list: ChangeList,
 1175    inline_value_cache: InlineValueCache,
 1176    selection_drag_state: SelectionDragState,
 1177    colors: Option<LspColorData>,
 1178    post_scroll_update: Task<()>,
 1179    refresh_colors_task: Task<()>,
 1180    inlay_hints: Option<LspInlayHintData>,
 1181    folding_newlines: Task<()>,
 1182    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1183}
 1184
 1185fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1186    if debounce_ms > 0 {
 1187        Some(Duration::from_millis(debounce_ms))
 1188    } else {
 1189        None
 1190    }
 1191}
 1192
 1193#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1194enum NextScrollCursorCenterTopBottom {
 1195    #[default]
 1196    Center,
 1197    Top,
 1198    Bottom,
 1199}
 1200
 1201impl NextScrollCursorCenterTopBottom {
 1202    fn next(&self) -> Self {
 1203        match self {
 1204            Self::Center => Self::Top,
 1205            Self::Top => Self::Bottom,
 1206            Self::Bottom => Self::Center,
 1207        }
 1208    }
 1209}
 1210
 1211#[derive(Clone)]
 1212pub struct EditorSnapshot {
 1213    pub mode: EditorMode,
 1214    show_gutter: bool,
 1215    show_line_numbers: Option<bool>,
 1216    show_git_diff_gutter: Option<bool>,
 1217    show_code_actions: Option<bool>,
 1218    show_runnables: Option<bool>,
 1219    show_breakpoints: Option<bool>,
 1220    git_blame_gutter_max_author_length: Option<usize>,
 1221    pub display_snapshot: DisplaySnapshot,
 1222    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1223    is_focused: bool,
 1224    scroll_anchor: ScrollAnchor,
 1225    ongoing_scroll: OngoingScroll,
 1226    current_line_highlight: CurrentLineHighlight,
 1227    gutter_hovered: bool,
 1228}
 1229
 1230#[derive(Default, Debug, Clone, Copy)]
 1231pub struct GutterDimensions {
 1232    pub left_padding: Pixels,
 1233    pub right_padding: Pixels,
 1234    pub width: Pixels,
 1235    pub margin: Pixels,
 1236    pub git_blame_entries_width: Option<Pixels>,
 1237}
 1238
 1239impl GutterDimensions {
 1240    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1241        Self {
 1242            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1243            ..Default::default()
 1244        }
 1245    }
 1246
 1247    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1248        -cx.text_system().descent(font_id, font_size)
 1249    }
 1250    /// The full width of the space taken up by the gutter.
 1251    pub fn full_width(&self) -> Pixels {
 1252        self.margin + self.width
 1253    }
 1254
 1255    /// The width of the space reserved for the fold indicators,
 1256    /// use alongside 'justify_end' and `gutter_width` to
 1257    /// right align content with the line numbers
 1258    pub fn fold_area_width(&self) -> Pixels {
 1259        self.margin + self.right_padding
 1260    }
 1261}
 1262
 1263struct CharacterDimensions {
 1264    em_width: Pixels,
 1265    em_advance: Pixels,
 1266    line_height: Pixels,
 1267}
 1268
 1269#[derive(Debug)]
 1270pub struct RemoteSelection {
 1271    pub replica_id: ReplicaId,
 1272    pub selection: Selection<Anchor>,
 1273    pub cursor_shape: CursorShape,
 1274    pub collaborator_id: CollaboratorId,
 1275    pub line_mode: bool,
 1276    pub user_name: Option<SharedString>,
 1277    pub color: PlayerColor,
 1278}
 1279
 1280#[derive(Clone, Debug)]
 1281struct SelectionHistoryEntry {
 1282    selections: Arc<[Selection<Anchor>]>,
 1283    select_next_state: Option<SelectNextState>,
 1284    select_prev_state: Option<SelectNextState>,
 1285    add_selections_state: Option<AddSelectionsState>,
 1286}
 1287
 1288#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1289enum SelectionHistoryMode {
 1290    Normal,
 1291    Undoing,
 1292    Redoing,
 1293    Skipping,
 1294}
 1295
 1296#[derive(Clone, PartialEq, Eq, Hash)]
 1297struct HoveredCursor {
 1298    replica_id: ReplicaId,
 1299    selection_id: usize,
 1300}
 1301
 1302impl Default for SelectionHistoryMode {
 1303    fn default() -> Self {
 1304        Self::Normal
 1305    }
 1306}
 1307
 1308#[derive(Debug)]
 1309/// SelectionEffects controls the side-effects of updating the selection.
 1310///
 1311/// The default behaviour does "what you mostly want":
 1312/// - it pushes to the nav history if the cursor moved by >10 lines
 1313/// - it re-triggers completion requests
 1314/// - it scrolls to fit
 1315///
 1316/// You might want to modify these behaviours. For example when doing a "jump"
 1317/// like go to definition, we always want to add to nav history; but when scrolling
 1318/// in vim mode we never do.
 1319///
 1320/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1321/// move.
 1322#[derive(Clone)]
 1323pub struct SelectionEffects {
 1324    nav_history: Option<bool>,
 1325    completions: bool,
 1326    scroll: Option<Autoscroll>,
 1327}
 1328
 1329impl Default for SelectionEffects {
 1330    fn default() -> Self {
 1331        Self {
 1332            nav_history: None,
 1333            completions: true,
 1334            scroll: Some(Autoscroll::fit()),
 1335        }
 1336    }
 1337}
 1338impl SelectionEffects {
 1339    pub fn scroll(scroll: Autoscroll) -> Self {
 1340        Self {
 1341            scroll: Some(scroll),
 1342            ..Default::default()
 1343        }
 1344    }
 1345
 1346    pub fn no_scroll() -> Self {
 1347        Self {
 1348            scroll: None,
 1349            ..Default::default()
 1350        }
 1351    }
 1352
 1353    pub fn completions(self, completions: bool) -> Self {
 1354        Self {
 1355            completions,
 1356            ..self
 1357        }
 1358    }
 1359
 1360    pub fn nav_history(self, nav_history: bool) -> Self {
 1361        Self {
 1362            nav_history: Some(nav_history),
 1363            ..self
 1364        }
 1365    }
 1366}
 1367
 1368struct DeferredSelectionEffectsState {
 1369    changed: bool,
 1370    effects: SelectionEffects,
 1371    old_cursor_position: Anchor,
 1372    history_entry: SelectionHistoryEntry,
 1373}
 1374
 1375#[derive(Default)]
 1376struct SelectionHistory {
 1377    #[allow(clippy::type_complexity)]
 1378    selections_by_transaction:
 1379        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1380    mode: SelectionHistoryMode,
 1381    undo_stack: VecDeque<SelectionHistoryEntry>,
 1382    redo_stack: VecDeque<SelectionHistoryEntry>,
 1383}
 1384
 1385impl SelectionHistory {
 1386    #[track_caller]
 1387    fn insert_transaction(
 1388        &mut self,
 1389        transaction_id: TransactionId,
 1390        selections: Arc<[Selection<Anchor>]>,
 1391    ) {
 1392        if selections.is_empty() {
 1393            log::error!(
 1394                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1395                std::panic::Location::caller()
 1396            );
 1397            return;
 1398        }
 1399        self.selections_by_transaction
 1400            .insert(transaction_id, (selections, None));
 1401    }
 1402
 1403    #[allow(clippy::type_complexity)]
 1404    fn transaction(
 1405        &self,
 1406        transaction_id: TransactionId,
 1407    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1408        self.selections_by_transaction.get(&transaction_id)
 1409    }
 1410
 1411    #[allow(clippy::type_complexity)]
 1412    fn transaction_mut(
 1413        &mut self,
 1414        transaction_id: TransactionId,
 1415    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1416        self.selections_by_transaction.get_mut(&transaction_id)
 1417    }
 1418
 1419    fn push(&mut self, entry: SelectionHistoryEntry) {
 1420        if !entry.selections.is_empty() {
 1421            match self.mode {
 1422                SelectionHistoryMode::Normal => {
 1423                    self.push_undo(entry);
 1424                    self.redo_stack.clear();
 1425                }
 1426                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1427                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1428                SelectionHistoryMode::Skipping => {}
 1429            }
 1430        }
 1431    }
 1432
 1433    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1434        if self
 1435            .undo_stack
 1436            .back()
 1437            .is_none_or(|e| e.selections != entry.selections)
 1438        {
 1439            self.undo_stack.push_back(entry);
 1440            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1441                self.undo_stack.pop_front();
 1442            }
 1443        }
 1444    }
 1445
 1446    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1447        if self
 1448            .redo_stack
 1449            .back()
 1450            .is_none_or(|e| e.selections != entry.selections)
 1451        {
 1452            self.redo_stack.push_back(entry);
 1453            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1454                self.redo_stack.pop_front();
 1455            }
 1456        }
 1457    }
 1458}
 1459
 1460#[derive(Clone, Copy)]
 1461pub struct RowHighlightOptions {
 1462    pub autoscroll: bool,
 1463    pub include_gutter: bool,
 1464}
 1465
 1466impl Default for RowHighlightOptions {
 1467    fn default() -> Self {
 1468        Self {
 1469            autoscroll: Default::default(),
 1470            include_gutter: true,
 1471        }
 1472    }
 1473}
 1474
 1475struct RowHighlight {
 1476    index: usize,
 1477    range: Range<Anchor>,
 1478    color: Hsla,
 1479    options: RowHighlightOptions,
 1480    type_id: TypeId,
 1481}
 1482
 1483#[derive(Clone, Debug)]
 1484struct AddSelectionsState {
 1485    groups: Vec<AddSelectionsGroup>,
 1486}
 1487
 1488#[derive(Clone, Debug)]
 1489struct AddSelectionsGroup {
 1490    above: bool,
 1491    stack: Vec<usize>,
 1492}
 1493
 1494#[derive(Clone)]
 1495struct SelectNextState {
 1496    query: AhoCorasick,
 1497    wordwise: bool,
 1498    done: bool,
 1499}
 1500
 1501impl std::fmt::Debug for SelectNextState {
 1502    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1503        f.debug_struct(std::any::type_name::<Self>())
 1504            .field("wordwise", &self.wordwise)
 1505            .field("done", &self.done)
 1506            .finish()
 1507    }
 1508}
 1509
 1510#[derive(Debug)]
 1511struct AutocloseRegion {
 1512    selection_id: usize,
 1513    range: Range<Anchor>,
 1514    pair: BracketPair,
 1515}
 1516
 1517#[derive(Debug)]
 1518struct SnippetState {
 1519    ranges: Vec<Vec<Range<Anchor>>>,
 1520    active_index: usize,
 1521    choices: Vec<Option<Vec<String>>>,
 1522}
 1523
 1524#[doc(hidden)]
 1525pub struct RenameState {
 1526    pub range: Range<Anchor>,
 1527    pub old_name: Arc<str>,
 1528    pub editor: Entity<Editor>,
 1529    block_id: CustomBlockId,
 1530}
 1531
 1532struct InvalidationStack<T>(Vec<T>);
 1533
 1534struct RegisteredEditPredictionProvider {
 1535    provider: Arc<dyn EditPredictionProviderHandle>,
 1536    _subscription: Subscription,
 1537}
 1538
 1539#[derive(Debug, PartialEq, Eq)]
 1540pub struct ActiveDiagnosticGroup {
 1541    pub active_range: Range<Anchor>,
 1542    pub active_message: String,
 1543    pub group_id: usize,
 1544    pub blocks: HashSet<CustomBlockId>,
 1545}
 1546
 1547#[derive(Debug, PartialEq, Eq)]
 1548
 1549pub(crate) enum ActiveDiagnostic {
 1550    None,
 1551    All,
 1552    Group(ActiveDiagnosticGroup),
 1553}
 1554
 1555#[derive(Serialize, Deserialize, Clone, Debug)]
 1556pub struct ClipboardSelection {
 1557    /// The number of bytes in this selection.
 1558    pub len: usize,
 1559    /// Whether this was a full-line selection.
 1560    pub is_entire_line: bool,
 1561    /// The indentation of the first line when this content was originally copied.
 1562    pub first_line_indent: u32,
 1563}
 1564
 1565// selections, scroll behavior, was newest selection reversed
 1566type SelectSyntaxNodeHistoryState = (
 1567    Box<[Selection<usize>]>,
 1568    SelectSyntaxNodeScrollBehavior,
 1569    bool,
 1570);
 1571
 1572#[derive(Default)]
 1573struct SelectSyntaxNodeHistory {
 1574    stack: Vec<SelectSyntaxNodeHistoryState>,
 1575    // disable temporarily to allow changing selections without losing the stack
 1576    pub disable_clearing: bool,
 1577}
 1578
 1579impl SelectSyntaxNodeHistory {
 1580    pub fn try_clear(&mut self) {
 1581        if !self.disable_clearing {
 1582            self.stack.clear();
 1583        }
 1584    }
 1585
 1586    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1587        self.stack.push(selection);
 1588    }
 1589
 1590    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1591        self.stack.pop()
 1592    }
 1593}
 1594
 1595enum SelectSyntaxNodeScrollBehavior {
 1596    CursorTop,
 1597    FitSelection,
 1598    CursorBottom,
 1599}
 1600
 1601#[derive(Debug)]
 1602pub(crate) struct NavigationData {
 1603    cursor_anchor: Anchor,
 1604    cursor_position: Point,
 1605    scroll_anchor: ScrollAnchor,
 1606    scroll_top_row: u32,
 1607}
 1608
 1609#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1610pub enum GotoDefinitionKind {
 1611    Symbol,
 1612    Declaration,
 1613    Type,
 1614    Implementation,
 1615}
 1616
 1617pub enum FormatTarget {
 1618    Buffers(HashSet<Entity<Buffer>>),
 1619    Ranges(Vec<Range<MultiBufferPoint>>),
 1620}
 1621
 1622pub(crate) struct FocusedBlock {
 1623    id: BlockId,
 1624    focus_handle: WeakFocusHandle,
 1625}
 1626
 1627#[derive(Clone)]
 1628enum JumpData {
 1629    MultiBufferRow {
 1630        row: MultiBufferRow,
 1631        line_offset_from_top: u32,
 1632    },
 1633    MultiBufferPoint {
 1634        excerpt_id: ExcerptId,
 1635        position: Point,
 1636        anchor: text::Anchor,
 1637        line_offset_from_top: u32,
 1638    },
 1639}
 1640
 1641pub enum MultibufferSelectionMode {
 1642    First,
 1643    All,
 1644}
 1645
 1646#[derive(Clone, Copy, Debug, Default)]
 1647pub struct RewrapOptions {
 1648    pub override_language_settings: bool,
 1649    pub preserve_existing_whitespace: bool,
 1650}
 1651
 1652impl Editor {
 1653    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1654        let buffer = cx.new(|cx| Buffer::local("", cx));
 1655        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1656        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1657    }
 1658
 1659    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1660        let buffer = cx.new(|cx| Buffer::local("", cx));
 1661        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1662        Self::new(EditorMode::full(), buffer, None, window, cx)
 1663    }
 1664
 1665    pub fn auto_height(
 1666        min_lines: usize,
 1667        max_lines: usize,
 1668        window: &mut Window,
 1669        cx: &mut Context<Self>,
 1670    ) -> Self {
 1671        let buffer = cx.new(|cx| Buffer::local("", cx));
 1672        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1673        Self::new(
 1674            EditorMode::AutoHeight {
 1675                min_lines,
 1676                max_lines: Some(max_lines),
 1677            },
 1678            buffer,
 1679            None,
 1680            window,
 1681            cx,
 1682        )
 1683    }
 1684
 1685    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1686    /// The editor grows as tall as needed to fit its content.
 1687    pub fn auto_height_unbounded(
 1688        min_lines: usize,
 1689        window: &mut Window,
 1690        cx: &mut Context<Self>,
 1691    ) -> Self {
 1692        let buffer = cx.new(|cx| Buffer::local("", cx));
 1693        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1694        Self::new(
 1695            EditorMode::AutoHeight {
 1696                min_lines,
 1697                max_lines: None,
 1698            },
 1699            buffer,
 1700            None,
 1701            window,
 1702            cx,
 1703        )
 1704    }
 1705
 1706    pub fn for_buffer(
 1707        buffer: Entity<Buffer>,
 1708        project: Option<Entity<Project>>,
 1709        window: &mut Window,
 1710        cx: &mut Context<Self>,
 1711    ) -> Self {
 1712        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1713        Self::new(EditorMode::full(), buffer, project, window, cx)
 1714    }
 1715
 1716    pub fn for_multibuffer(
 1717        buffer: Entity<MultiBuffer>,
 1718        project: Option<Entity<Project>>,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        Self::new(EditorMode::full(), buffer, project, window, cx)
 1723    }
 1724
 1725    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1726        let mut clone = Self::new(
 1727            self.mode.clone(),
 1728            self.buffer.clone(),
 1729            self.project.clone(),
 1730            window,
 1731            cx,
 1732        );
 1733        self.display_map.update(cx, |display_map, cx| {
 1734            let snapshot = display_map.snapshot(cx);
 1735            clone.display_map.update(cx, |display_map, cx| {
 1736                display_map.set_state(&snapshot, cx);
 1737            });
 1738        });
 1739        clone.folds_did_change(cx);
 1740        clone.selections.clone_state(&self.selections);
 1741        clone.scroll_manager.clone_state(&self.scroll_manager);
 1742        clone.searchable = self.searchable;
 1743        clone.read_only = self.read_only;
 1744        clone
 1745    }
 1746
 1747    pub fn new(
 1748        mode: EditorMode,
 1749        buffer: Entity<MultiBuffer>,
 1750        project: Option<Entity<Project>>,
 1751        window: &mut Window,
 1752        cx: &mut Context<Self>,
 1753    ) -> Self {
 1754        Editor::new_internal(mode, buffer, project, None, window, cx)
 1755    }
 1756
 1757    fn new_internal(
 1758        mode: EditorMode,
 1759        multi_buffer: Entity<MultiBuffer>,
 1760        project: Option<Entity<Project>>,
 1761        display_map: Option<Entity<DisplayMap>>,
 1762        window: &mut Window,
 1763        cx: &mut Context<Self>,
 1764    ) -> Self {
 1765        debug_assert!(
 1766            display_map.is_none() || mode.is_minimap(),
 1767            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1768        );
 1769
 1770        let full_mode = mode.is_full();
 1771        let is_minimap = mode.is_minimap();
 1772        let diagnostics_max_severity = if full_mode {
 1773            EditorSettings::get_global(cx)
 1774                .diagnostics_max_severity
 1775                .unwrap_or(DiagnosticSeverity::Hint)
 1776        } else {
 1777            DiagnosticSeverity::Off
 1778        };
 1779        let style = window.text_style();
 1780        let font_size = style.font_size.to_pixels(window.rem_size());
 1781        let editor = cx.entity().downgrade();
 1782        let fold_placeholder = FoldPlaceholder {
 1783            constrain_width: false,
 1784            render: Arc::new(move |fold_id, fold_range, cx| {
 1785                let editor = editor.clone();
 1786                div()
 1787                    .id(fold_id)
 1788                    .bg(cx.theme().colors().ghost_element_background)
 1789                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1790                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1791                    .rounded_xs()
 1792                    .size_full()
 1793                    .cursor_pointer()
 1794                    .child("")
 1795                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1796                    .on_click(move |_, _window, cx| {
 1797                        editor
 1798                            .update(cx, |editor, cx| {
 1799                                editor.unfold_ranges(
 1800                                    &[fold_range.start..fold_range.end],
 1801                                    true,
 1802                                    false,
 1803                                    cx,
 1804                                );
 1805                                cx.stop_propagation();
 1806                            })
 1807                            .ok();
 1808                    })
 1809                    .into_any()
 1810            }),
 1811            merge_adjacent: true,
 1812            ..FoldPlaceholder::default()
 1813        };
 1814        let display_map = display_map.unwrap_or_else(|| {
 1815            cx.new(|cx| {
 1816                DisplayMap::new(
 1817                    multi_buffer.clone(),
 1818                    style.font(),
 1819                    font_size,
 1820                    None,
 1821                    FILE_HEADER_HEIGHT,
 1822                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1823                    fold_placeholder,
 1824                    diagnostics_max_severity,
 1825                    cx,
 1826                )
 1827            })
 1828        });
 1829
 1830        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1831
 1832        let blink_manager = cx.new(|cx| {
 1833            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1834            if is_minimap {
 1835                blink_manager.disable(cx);
 1836            }
 1837            blink_manager
 1838        });
 1839
 1840        let soft_wrap_mode_override =
 1841            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1842
 1843        let mut project_subscriptions = Vec::new();
 1844        if full_mode && let Some(project) = project.as_ref() {
 1845            project_subscriptions.push(cx.subscribe_in(
 1846                project,
 1847                window,
 1848                |editor, _, event, window, cx| match event {
 1849                    project::Event::RefreshCodeLens => {
 1850                        // we always query lens with actions, without storing them, always refreshing them
 1851                    }
 1852                    project::Event::RefreshInlayHints {
 1853                        server_id,
 1854                        request_id,
 1855                    } => {
 1856                        editor.refresh_inlay_hints(
 1857                            InlayHintRefreshReason::RefreshRequested {
 1858                                server_id: *server_id,
 1859                                request_id: *request_id,
 1860                            },
 1861                            cx,
 1862                        );
 1863                    }
 1864                    project::Event::LanguageServerRemoved(..) => {
 1865                        if editor.tasks_update_task.is_none() {
 1866                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1867                        }
 1868                        editor.registered_buffers.clear();
 1869                        editor.register_visible_buffers(cx);
 1870                    }
 1871                    project::Event::LanguageServerAdded(..) => {
 1872                        if editor.tasks_update_task.is_none() {
 1873                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1874                        }
 1875                    }
 1876                    project::Event::SnippetEdit(id, snippet_edits) => {
 1877                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1878                            let focus_handle = editor.focus_handle(cx);
 1879                            if focus_handle.is_focused(window) {
 1880                                let snapshot = buffer.read(cx).snapshot();
 1881                                for (range, snippet) in snippet_edits {
 1882                                    let editor_range =
 1883                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1884                                    editor
 1885                                        .insert_snippet(
 1886                                            &[editor_range],
 1887                                            snippet.clone(),
 1888                                            window,
 1889                                            cx,
 1890                                        )
 1891                                        .ok();
 1892                                }
 1893                            }
 1894                        }
 1895                    }
 1896                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1897                        let buffer_id = *buffer_id;
 1898                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1899                            editor.register_buffer(buffer_id, cx);
 1900                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1901                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1902                            refresh_linked_ranges(editor, window, cx);
 1903                            editor.refresh_code_actions(window, cx);
 1904                            editor.refresh_document_highlights(cx);
 1905                        }
 1906                    }
 1907
 1908                    project::Event::EntryRenamed(transaction) => {
 1909                        let Some(workspace) = editor.workspace() else {
 1910                            return;
 1911                        };
 1912                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1913                        else {
 1914                            return;
 1915                        };
 1916                        if active_editor.entity_id() == cx.entity_id() {
 1917                            let edited_buffers_already_open = {
 1918                                let other_editors: Vec<Entity<Editor>> = workspace
 1919                                    .read(cx)
 1920                                    .panes()
 1921                                    .iter()
 1922                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1923                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1924                                    .collect();
 1925
 1926                                transaction.0.keys().all(|buffer| {
 1927                                    other_editors.iter().any(|editor| {
 1928                                        let multi_buffer = editor.read(cx).buffer();
 1929                                        multi_buffer.read(cx).is_singleton()
 1930                                            && multi_buffer.read(cx).as_singleton().map_or(
 1931                                                false,
 1932                                                |singleton| {
 1933                                                    singleton.entity_id() == buffer.entity_id()
 1934                                                },
 1935                                            )
 1936                                    })
 1937                                })
 1938                            };
 1939
 1940                            if !edited_buffers_already_open {
 1941                                let workspace = workspace.downgrade();
 1942                                let transaction = transaction.clone();
 1943                                cx.defer_in(window, move |_, window, cx| {
 1944                                    cx.spawn_in(window, async move |editor, cx| {
 1945                                        Self::open_project_transaction(
 1946                                            &editor,
 1947                                            workspace,
 1948                                            transaction,
 1949                                            "Rename".to_string(),
 1950                                            cx,
 1951                                        )
 1952                                        .await
 1953                                        .ok()
 1954                                    })
 1955                                    .detach();
 1956                                });
 1957                            }
 1958                        }
 1959                    }
 1960
 1961                    _ => {}
 1962                },
 1963            ));
 1964            if let Some(task_inventory) = project
 1965                .read(cx)
 1966                .task_store()
 1967                .read(cx)
 1968                .task_inventory()
 1969                .cloned()
 1970            {
 1971                project_subscriptions.push(cx.observe_in(
 1972                    &task_inventory,
 1973                    window,
 1974                    |editor, _, window, cx| {
 1975                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1976                    },
 1977                ));
 1978            };
 1979
 1980            project_subscriptions.push(cx.subscribe_in(
 1981                &project.read(cx).breakpoint_store(),
 1982                window,
 1983                |editor, _, event, window, cx| match event {
 1984                    BreakpointStoreEvent::ClearDebugLines => {
 1985                        editor.clear_row_highlights::<ActiveDebugLine>();
 1986                        editor.refresh_inline_values(cx);
 1987                    }
 1988                    BreakpointStoreEvent::SetDebugLine => {
 1989                        if editor.go_to_active_debug_line(window, cx) {
 1990                            cx.stop_propagation();
 1991                        }
 1992
 1993                        editor.refresh_inline_values(cx);
 1994                    }
 1995                    _ => {}
 1996                },
 1997            ));
 1998            let git_store = project.read(cx).git_store().clone();
 1999            let project = project.clone();
 2000            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2001                if let GitStoreEvent::RepositoryAdded = event {
 2002                    this.load_diff_task = Some(
 2003                        update_uncommitted_diff_for_buffer(
 2004                            cx.entity(),
 2005                            &project,
 2006                            this.buffer.read(cx).all_buffers(),
 2007                            this.buffer.clone(),
 2008                            cx,
 2009                        )
 2010                        .shared(),
 2011                    );
 2012                }
 2013            }));
 2014        }
 2015
 2016        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2017
 2018        let inlay_hint_settings =
 2019            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2020        let focus_handle = cx.focus_handle();
 2021        if !is_minimap {
 2022            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2023                .detach();
 2024            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2025                .detach();
 2026            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2027                .detach();
 2028            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2029                .detach();
 2030            cx.observe_pending_input(window, Self::observe_pending_input)
 2031                .detach();
 2032        }
 2033
 2034        let show_indent_guides =
 2035            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2036                Some(false)
 2037            } else {
 2038                None
 2039            };
 2040
 2041        let breakpoint_store = match (&mode, project.as_ref()) {
 2042            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2043            _ => None,
 2044        };
 2045
 2046        let mut code_action_providers = Vec::new();
 2047        let mut load_uncommitted_diff = None;
 2048        if let Some(project) = project.clone() {
 2049            load_uncommitted_diff = Some(
 2050                update_uncommitted_diff_for_buffer(
 2051                    cx.entity(),
 2052                    &project,
 2053                    multi_buffer.read(cx).all_buffers(),
 2054                    multi_buffer.clone(),
 2055                    cx,
 2056                )
 2057                .shared(),
 2058            );
 2059            code_action_providers.push(Rc::new(project) as Rc<_>);
 2060        }
 2061
 2062        let mut editor = Self {
 2063            focus_handle,
 2064            show_cursor_when_unfocused: false,
 2065            last_focused_descendant: None,
 2066            buffer: multi_buffer.clone(),
 2067            display_map: display_map.clone(),
 2068            placeholder_display_map: None,
 2069            selections,
 2070            scroll_manager: ScrollManager::new(cx),
 2071            columnar_selection_state: None,
 2072            add_selections_state: None,
 2073            select_next_state: None,
 2074            select_prev_state: None,
 2075            selection_history: SelectionHistory::default(),
 2076            defer_selection_effects: false,
 2077            deferred_selection_effects_state: None,
 2078            autoclose_regions: Vec::new(),
 2079            snippet_stack: InvalidationStack::default(),
 2080            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2081            ime_transaction: None,
 2082            active_diagnostics: ActiveDiagnostic::None,
 2083            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2084            inline_diagnostics_update: Task::ready(()),
 2085            inline_diagnostics: Vec::new(),
 2086            soft_wrap_mode_override,
 2087            diagnostics_max_severity,
 2088            hard_wrap: None,
 2089            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2090            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2091            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2092            project,
 2093            blink_manager: blink_manager.clone(),
 2094            show_local_selections: true,
 2095            show_scrollbars: ScrollbarAxes {
 2096                horizontal: full_mode,
 2097                vertical: full_mode,
 2098            },
 2099            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2100            offset_content: !matches!(mode, EditorMode::SingleLine),
 2101            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2102            show_gutter: full_mode,
 2103            show_line_numbers: (!full_mode).then_some(false),
 2104            use_relative_line_numbers: None,
 2105            disable_expand_excerpt_buttons: !full_mode,
 2106            show_git_diff_gutter: None,
 2107            show_code_actions: None,
 2108            show_runnables: None,
 2109            show_breakpoints: None,
 2110            show_wrap_guides: None,
 2111            show_indent_guides,
 2112            highlight_order: 0,
 2113            highlighted_rows: HashMap::default(),
 2114            background_highlights: HashMap::default(),
 2115            gutter_highlights: HashMap::default(),
 2116            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2117            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2118            nav_history: None,
 2119            context_menu: RefCell::new(None),
 2120            context_menu_options: None,
 2121            mouse_context_menu: None,
 2122            completion_tasks: Vec::new(),
 2123            inline_blame_popover: None,
 2124            inline_blame_popover_show_task: None,
 2125            signature_help_state: SignatureHelpState::default(),
 2126            auto_signature_help: None,
 2127            find_all_references_task_sources: Vec::new(),
 2128            next_completion_id: 0,
 2129            next_inlay_id: 0,
 2130            code_action_providers,
 2131            available_code_actions: None,
 2132            code_actions_task: None,
 2133            quick_selection_highlight_task: None,
 2134            debounced_selection_highlight_task: None,
 2135            document_highlights_task: None,
 2136            linked_editing_range_task: None,
 2137            pending_rename: None,
 2138            searchable: !is_minimap,
 2139            cursor_shape: EditorSettings::get_global(cx)
 2140                .cursor_shape
 2141                .unwrap_or_default(),
 2142            current_line_highlight: None,
 2143            autoindent_mode: Some(AutoindentMode::EachLine),
 2144
 2145            workspace: None,
 2146            input_enabled: !is_minimap,
 2147            use_modal_editing: full_mode,
 2148            read_only: is_minimap,
 2149            use_autoclose: true,
 2150            use_auto_surround: true,
 2151            auto_replace_emoji_shortcode: false,
 2152            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2153            leader_id: None,
 2154            remote_id: None,
 2155            hover_state: HoverState::default(),
 2156            pending_mouse_down: None,
 2157            hovered_link_state: None,
 2158            edit_prediction_provider: None,
 2159            active_edit_prediction: None,
 2160            stale_edit_prediction_in_menu: None,
 2161            edit_prediction_preview: EditPredictionPreview::Inactive {
 2162                released_too_fast: false,
 2163            },
 2164            inline_diagnostics_enabled: full_mode,
 2165            diagnostics_enabled: full_mode,
 2166            word_completions_enabled: full_mode,
 2167            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2168            gutter_hovered: false,
 2169            pixel_position_of_newest_cursor: None,
 2170            last_bounds: None,
 2171            last_position_map: None,
 2172            expect_bounds_change: None,
 2173            gutter_dimensions: GutterDimensions::default(),
 2174            style: None,
 2175            show_cursor_names: false,
 2176            hovered_cursors: HashMap::default(),
 2177            next_editor_action_id: EditorActionId::default(),
 2178            editor_actions: Rc::default(),
 2179            edit_predictions_hidden_for_vim_mode: false,
 2180            show_edit_predictions_override: None,
 2181            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2182            edit_prediction_settings: EditPredictionSettings::Disabled,
 2183            edit_prediction_indent_conflict: false,
 2184            edit_prediction_requires_modifier_in_indent_conflict: true,
 2185            custom_context_menu: None,
 2186            show_git_blame_gutter: false,
 2187            show_git_blame_inline: false,
 2188            show_selection_menu: None,
 2189            show_git_blame_inline_delay_task: None,
 2190            git_blame_inline_enabled: full_mode
 2191                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2192            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2193            serialize_dirty_buffers: !is_minimap
 2194                && ProjectSettings::get_global(cx)
 2195                    .session
 2196                    .restore_unsaved_buffers,
 2197            blame: None,
 2198            blame_subscription: None,
 2199            tasks: BTreeMap::default(),
 2200
 2201            breakpoint_store,
 2202            gutter_breakpoint_indicator: (None, None),
 2203            hovered_diff_hunk_row: None,
 2204            _subscriptions: (!is_minimap)
 2205                .then(|| {
 2206                    vec![
 2207                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2208                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2209                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2210                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2211                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2212                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2213                        cx.observe_window_activation(window, |editor, window, cx| {
 2214                            let active = window.is_window_active();
 2215                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2216                                if active {
 2217                                    blink_manager.enable(cx);
 2218                                } else {
 2219                                    blink_manager.disable(cx);
 2220                                }
 2221                            });
 2222                            if active {
 2223                                editor.show_mouse_cursor(cx);
 2224                            }
 2225                        }),
 2226                    ]
 2227                })
 2228                .unwrap_or_default(),
 2229            tasks_update_task: None,
 2230            pull_diagnostics_task: Task::ready(()),
 2231            colors: None,
 2232            refresh_colors_task: Task::ready(()),
 2233            inlay_hints: None,
 2234            next_color_inlay_id: 0,
 2235            post_scroll_update: Task::ready(()),
 2236            linked_edit_ranges: Default::default(),
 2237            in_project_search: false,
 2238            previous_search_ranges: None,
 2239            breadcrumb_header: None,
 2240            focused_block: None,
 2241            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2242            addons: HashMap::default(),
 2243            registered_buffers: HashMap::default(),
 2244            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2245            selection_mark_mode: false,
 2246            toggle_fold_multiple_buffers: Task::ready(()),
 2247            serialize_selections: Task::ready(()),
 2248            serialize_folds: Task::ready(()),
 2249            text_style_refinement: None,
 2250            load_diff_task: load_uncommitted_diff,
 2251            temporary_diff_override: false,
 2252            mouse_cursor_hidden: false,
 2253            minimap: None,
 2254            hide_mouse_mode: EditorSettings::get_global(cx)
 2255                .hide_mouse
 2256                .unwrap_or_default(),
 2257            change_list: ChangeList::new(),
 2258            mode,
 2259            selection_drag_state: SelectionDragState::None,
 2260            folding_newlines: Task::ready(()),
 2261            lookup_key: None,
 2262        };
 2263
 2264        if is_minimap {
 2265            return editor;
 2266        }
 2267
 2268        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2269            editor
 2270                ._subscriptions
 2271                .push(cx.observe(breakpoints, |_, _, cx| {
 2272                    cx.notify();
 2273                }));
 2274        }
 2275        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2276        editor._subscriptions.extend(project_subscriptions);
 2277
 2278        editor._subscriptions.push(cx.subscribe_in(
 2279            &cx.entity(),
 2280            window,
 2281            |editor, _, e: &EditorEvent, window, cx| match e {
 2282                EditorEvent::ScrollPositionChanged { local, .. } => {
 2283                    if *local {
 2284                        let new_anchor = editor.scroll_manager.anchor();
 2285                        let snapshot = editor.snapshot(window, cx);
 2286                        editor.update_restoration_data(cx, move |data| {
 2287                            data.scroll_position = (
 2288                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2289                                new_anchor.offset,
 2290                            );
 2291                        });
 2292                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2293                        editor.inline_blame_popover.take();
 2294                    }
 2295                }
 2296                EditorEvent::Edited { .. } => {
 2297                    if vim_flavor(cx).is_none() {
 2298                        let display_map = editor.display_snapshot(cx);
 2299                        let selections = editor.selections.all_adjusted_display(&display_map);
 2300                        let pop_state = editor
 2301                            .change_list
 2302                            .last()
 2303                            .map(|previous| {
 2304                                previous.len() == selections.len()
 2305                                    && previous.iter().enumerate().all(|(ix, p)| {
 2306                                        p.to_display_point(&display_map).row()
 2307                                            == selections[ix].head().row()
 2308                                    })
 2309                            })
 2310                            .unwrap_or(false);
 2311                        let new_positions = selections
 2312                            .into_iter()
 2313                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2314                            .collect();
 2315                        editor
 2316                            .change_list
 2317                            .push_to_change_list(pop_state, new_positions);
 2318                    }
 2319                }
 2320                _ => (),
 2321            },
 2322        ));
 2323
 2324        if let Some(dap_store) = editor
 2325            .project
 2326            .as_ref()
 2327            .map(|project| project.read(cx).dap_store())
 2328        {
 2329            let weak_editor = cx.weak_entity();
 2330
 2331            editor
 2332                ._subscriptions
 2333                .push(
 2334                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2335                        let session_entity = cx.entity();
 2336                        weak_editor
 2337                            .update(cx, |editor, cx| {
 2338                                editor._subscriptions.push(
 2339                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2340                                );
 2341                            })
 2342                            .ok();
 2343                    }),
 2344                );
 2345
 2346            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2347                editor
 2348                    ._subscriptions
 2349                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2350            }
 2351        }
 2352
 2353        // skip adding the initial selection to selection history
 2354        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2355        editor.end_selection(window, cx);
 2356        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2357
 2358        editor.scroll_manager.show_scrollbars(window, cx);
 2359        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2360
 2361        if full_mode {
 2362            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2363            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2364
 2365            if editor.git_blame_inline_enabled {
 2366                editor.start_git_blame_inline(false, window, cx);
 2367            }
 2368
 2369            editor.go_to_active_debug_line(window, cx);
 2370
 2371            editor.minimap =
 2372                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2373            editor.colors = Some(LspColorData::new(cx));
 2374            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2375
 2376            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2377                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2378            }
 2379            editor.update_lsp_data(None, window, cx);
 2380            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2381        }
 2382
 2383        editor
 2384    }
 2385
 2386    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2387        self.selections.display_map(cx)
 2388    }
 2389
 2390    pub fn deploy_mouse_context_menu(
 2391        &mut self,
 2392        position: gpui::Point<Pixels>,
 2393        context_menu: Entity<ContextMenu>,
 2394        window: &mut Window,
 2395        cx: &mut Context<Self>,
 2396    ) {
 2397        self.mouse_context_menu = Some(MouseContextMenu::new(
 2398            self,
 2399            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2400            context_menu,
 2401            window,
 2402            cx,
 2403        ));
 2404    }
 2405
 2406    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2407        self.mouse_context_menu
 2408            .as_ref()
 2409            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2410    }
 2411
 2412    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2413        if self
 2414            .selections
 2415            .pending_anchor()
 2416            .is_some_and(|pending_selection| {
 2417                let snapshot = self.buffer().read(cx).snapshot(cx);
 2418                pending_selection.range().includes(range, &snapshot)
 2419            })
 2420        {
 2421            return true;
 2422        }
 2423
 2424        self.selections
 2425            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2426            .into_iter()
 2427            .any(|selection| {
 2428                // This is needed to cover a corner case, if we just check for an existing
 2429                // selection in the fold range, having a cursor at the start of the fold
 2430                // marks it as selected. Non-empty selections don't cause this.
 2431                let length = selection.end - selection.start;
 2432                length > 0
 2433            })
 2434    }
 2435
 2436    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2437        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2438    }
 2439
 2440    fn key_context_internal(
 2441        &self,
 2442        has_active_edit_prediction: bool,
 2443        window: &mut Window,
 2444        cx: &mut App,
 2445    ) -> KeyContext {
 2446        let mut key_context = KeyContext::new_with_defaults();
 2447        key_context.add("Editor");
 2448        let mode = match self.mode {
 2449            EditorMode::SingleLine => "single_line",
 2450            EditorMode::AutoHeight { .. } => "auto_height",
 2451            EditorMode::Minimap { .. } => "minimap",
 2452            EditorMode::Full { .. } => "full",
 2453        };
 2454
 2455        if EditorSettings::jupyter_enabled(cx) {
 2456            key_context.add("jupyter");
 2457        }
 2458
 2459        key_context.set("mode", mode);
 2460        if self.pending_rename.is_some() {
 2461            key_context.add("renaming");
 2462        }
 2463
 2464        match self.context_menu.borrow().as_ref() {
 2465            Some(CodeContextMenu::Completions(menu)) => {
 2466                if menu.visible() {
 2467                    key_context.add("menu");
 2468                    key_context.add("showing_completions");
 2469                }
 2470            }
 2471            Some(CodeContextMenu::CodeActions(menu)) => {
 2472                if menu.visible() {
 2473                    key_context.add("menu");
 2474                    key_context.add("showing_code_actions")
 2475                }
 2476            }
 2477            None => {}
 2478        }
 2479
 2480        if self.signature_help_state.has_multiple_signatures() {
 2481            key_context.add("showing_signature_help");
 2482        }
 2483
 2484        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2485        if !self.focus_handle(cx).contains_focused(window, cx)
 2486            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2487        {
 2488            for addon in self.addons.values() {
 2489                addon.extend_key_context(&mut key_context, cx)
 2490            }
 2491        }
 2492
 2493        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2494            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2495                Some(
 2496                    file.full_path(cx)
 2497                        .extension()?
 2498                        .to_string_lossy()
 2499                        .into_owned(),
 2500                )
 2501            }) {
 2502                key_context.set("extension", extension);
 2503            }
 2504        } else {
 2505            key_context.add("multibuffer");
 2506        }
 2507
 2508        if has_active_edit_prediction {
 2509            if self.edit_prediction_in_conflict() {
 2510                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2511            } else {
 2512                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2513                key_context.add("copilot_suggestion");
 2514            }
 2515        }
 2516
 2517        if self.selection_mark_mode {
 2518            key_context.add("selection_mode");
 2519        }
 2520
 2521        let disjoint = self.selections.disjoint_anchors();
 2522        let snapshot = self.snapshot(window, cx);
 2523        let snapshot = snapshot.buffer_snapshot();
 2524        if self.mode == EditorMode::SingleLine
 2525            && let [selection] = disjoint
 2526            && selection.start == selection.end
 2527            && selection.end.to_offset(snapshot) == snapshot.len()
 2528        {
 2529            key_context.add("end_of_input");
 2530        }
 2531
 2532        key_context
 2533    }
 2534
 2535    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2536        self.last_bounds.as_ref()
 2537    }
 2538
 2539    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2540        if self.mouse_cursor_hidden {
 2541            self.mouse_cursor_hidden = false;
 2542            cx.notify();
 2543        }
 2544    }
 2545
 2546    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2547        let hide_mouse_cursor = match origin {
 2548            HideMouseCursorOrigin::TypingAction => {
 2549                matches!(
 2550                    self.hide_mouse_mode,
 2551                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2552                )
 2553            }
 2554            HideMouseCursorOrigin::MovementAction => {
 2555                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2556            }
 2557        };
 2558        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2559            self.mouse_cursor_hidden = hide_mouse_cursor;
 2560            cx.notify();
 2561        }
 2562    }
 2563
 2564    pub fn edit_prediction_in_conflict(&self) -> bool {
 2565        if !self.show_edit_predictions_in_menu() {
 2566            return false;
 2567        }
 2568
 2569        let showing_completions = self
 2570            .context_menu
 2571            .borrow()
 2572            .as_ref()
 2573            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2574
 2575        showing_completions
 2576            || self.edit_prediction_requires_modifier()
 2577            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2578            // bindings to insert tab characters.
 2579            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2580    }
 2581
 2582    pub fn accept_edit_prediction_keybind(
 2583        &self,
 2584        accept_partial: bool,
 2585        window: &mut Window,
 2586        cx: &mut App,
 2587    ) -> AcceptEditPredictionBinding {
 2588        let key_context = self.key_context_internal(true, window, cx);
 2589        let in_conflict = self.edit_prediction_in_conflict();
 2590
 2591        let bindings = if accept_partial {
 2592            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2593        } else {
 2594            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2595        };
 2596
 2597        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2598        // just the first one.
 2599        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2600            !in_conflict
 2601                || binding
 2602                    .keystrokes()
 2603                    .first()
 2604                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2605        }))
 2606    }
 2607
 2608    pub fn new_file(
 2609        workspace: &mut Workspace,
 2610        _: &workspace::NewFile,
 2611        window: &mut Window,
 2612        cx: &mut Context<Workspace>,
 2613    ) {
 2614        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2615            "Failed to create buffer",
 2616            window,
 2617            cx,
 2618            |e, _, _| match e.error_code() {
 2619                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2620                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2621                e.error_tag("required").unwrap_or("the latest version")
 2622            )),
 2623                _ => None,
 2624            },
 2625        );
 2626    }
 2627
 2628    pub fn new_in_workspace(
 2629        workspace: &mut Workspace,
 2630        window: &mut Window,
 2631        cx: &mut Context<Workspace>,
 2632    ) -> Task<Result<Entity<Editor>>> {
 2633        let project = workspace.project().clone();
 2634        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2635
 2636        cx.spawn_in(window, async move |workspace, cx| {
 2637            let buffer = create.await?;
 2638            workspace.update_in(cx, |workspace, window, cx| {
 2639                let editor =
 2640                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2641                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2642                editor
 2643            })
 2644        })
 2645    }
 2646
 2647    fn new_file_vertical(
 2648        workspace: &mut Workspace,
 2649        _: &workspace::NewFileSplitVertical,
 2650        window: &mut Window,
 2651        cx: &mut Context<Workspace>,
 2652    ) {
 2653        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2654    }
 2655
 2656    fn new_file_horizontal(
 2657        workspace: &mut Workspace,
 2658        _: &workspace::NewFileSplitHorizontal,
 2659        window: &mut Window,
 2660        cx: &mut Context<Workspace>,
 2661    ) {
 2662        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2663    }
 2664
 2665    fn new_file_split(
 2666        workspace: &mut Workspace,
 2667        action: &workspace::NewFileSplit,
 2668        window: &mut Window,
 2669        cx: &mut Context<Workspace>,
 2670    ) {
 2671        Self::new_file_in_direction(workspace, action.0, window, cx)
 2672    }
 2673
 2674    fn new_file_in_direction(
 2675        workspace: &mut Workspace,
 2676        direction: SplitDirection,
 2677        window: &mut Window,
 2678        cx: &mut Context<Workspace>,
 2679    ) {
 2680        let project = workspace.project().clone();
 2681        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2682
 2683        cx.spawn_in(window, async move |workspace, cx| {
 2684            let buffer = create.await?;
 2685            workspace.update_in(cx, move |workspace, window, cx| {
 2686                workspace.split_item(
 2687                    direction,
 2688                    Box::new(
 2689                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2690                    ),
 2691                    window,
 2692                    cx,
 2693                )
 2694            })?;
 2695            anyhow::Ok(())
 2696        })
 2697        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2698            match e.error_code() {
 2699                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2700                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2701                e.error_tag("required").unwrap_or("the latest version")
 2702            )),
 2703                _ => None,
 2704            }
 2705        });
 2706    }
 2707
 2708    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2709        self.leader_id
 2710    }
 2711
 2712    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2713        &self.buffer
 2714    }
 2715
 2716    pub fn project(&self) -> Option<&Entity<Project>> {
 2717        self.project.as_ref()
 2718    }
 2719
 2720    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2721        self.workspace.as_ref()?.0.upgrade()
 2722    }
 2723
 2724    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2725        self.buffer().read(cx).title(cx)
 2726    }
 2727
 2728    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2729        let git_blame_gutter_max_author_length = self
 2730            .render_git_blame_gutter(cx)
 2731            .then(|| {
 2732                if let Some(blame) = self.blame.as_ref() {
 2733                    let max_author_length =
 2734                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2735                    Some(max_author_length)
 2736                } else {
 2737                    None
 2738                }
 2739            })
 2740            .flatten();
 2741
 2742        EditorSnapshot {
 2743            mode: self.mode.clone(),
 2744            show_gutter: self.show_gutter,
 2745            show_line_numbers: self.show_line_numbers,
 2746            show_git_diff_gutter: self.show_git_diff_gutter,
 2747            show_code_actions: self.show_code_actions,
 2748            show_runnables: self.show_runnables,
 2749            show_breakpoints: self.show_breakpoints,
 2750            git_blame_gutter_max_author_length,
 2751            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2752            placeholder_display_snapshot: self
 2753                .placeholder_display_map
 2754                .as_ref()
 2755                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2756            scroll_anchor: self.scroll_manager.anchor(),
 2757            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2758            is_focused: self.focus_handle.is_focused(window),
 2759            current_line_highlight: self
 2760                .current_line_highlight
 2761                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2762            gutter_hovered: self.gutter_hovered,
 2763        }
 2764    }
 2765
 2766    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2767        self.buffer.read(cx).language_at(point, cx)
 2768    }
 2769
 2770    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2771        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2772    }
 2773
 2774    pub fn active_excerpt(
 2775        &self,
 2776        cx: &App,
 2777    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2778        self.buffer
 2779            .read(cx)
 2780            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2781    }
 2782
 2783    pub fn mode(&self) -> &EditorMode {
 2784        &self.mode
 2785    }
 2786
 2787    pub fn set_mode(&mut self, mode: EditorMode) {
 2788        self.mode = mode;
 2789    }
 2790
 2791    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2792        self.collaboration_hub.as_deref()
 2793    }
 2794
 2795    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2796        self.collaboration_hub = Some(hub);
 2797    }
 2798
 2799    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2800        self.in_project_search = in_project_search;
 2801    }
 2802
 2803    pub fn set_custom_context_menu(
 2804        &mut self,
 2805        f: impl 'static
 2806        + Fn(
 2807            &mut Self,
 2808            DisplayPoint,
 2809            &mut Window,
 2810            &mut Context<Self>,
 2811        ) -> Option<Entity<ui::ContextMenu>>,
 2812    ) {
 2813        self.custom_context_menu = Some(Box::new(f))
 2814    }
 2815
 2816    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2817        self.completion_provider = provider;
 2818    }
 2819
 2820    #[cfg(any(test, feature = "test-support"))]
 2821    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2822        self.completion_provider.clone()
 2823    }
 2824
 2825    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2826        self.semantics_provider.clone()
 2827    }
 2828
 2829    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2830        self.semantics_provider = provider;
 2831    }
 2832
 2833    pub fn set_edit_prediction_provider<T>(
 2834        &mut self,
 2835        provider: Option<Entity<T>>,
 2836        window: &mut Window,
 2837        cx: &mut Context<Self>,
 2838    ) where
 2839        T: EditPredictionProvider,
 2840    {
 2841        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2842            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2843                if this.focus_handle.is_focused(window) {
 2844                    this.update_visible_edit_prediction(window, cx);
 2845                }
 2846            }),
 2847            provider: Arc::new(provider),
 2848        });
 2849        self.update_edit_prediction_settings(cx);
 2850        self.refresh_edit_prediction(false, false, window, cx);
 2851    }
 2852
 2853    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2854        self.placeholder_display_map
 2855            .as_ref()
 2856            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2857    }
 2858
 2859    pub fn set_placeholder_text(
 2860        &mut self,
 2861        placeholder_text: &str,
 2862        window: &mut Window,
 2863        cx: &mut Context<Self>,
 2864    ) {
 2865        let multibuffer = cx
 2866            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2867
 2868        let style = window.text_style();
 2869
 2870        self.placeholder_display_map = Some(cx.new(|cx| {
 2871            DisplayMap::new(
 2872                multibuffer,
 2873                style.font(),
 2874                style.font_size.to_pixels(window.rem_size()),
 2875                None,
 2876                FILE_HEADER_HEIGHT,
 2877                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2878                Default::default(),
 2879                DiagnosticSeverity::Off,
 2880                cx,
 2881            )
 2882        }));
 2883        cx.notify();
 2884    }
 2885
 2886    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2887        self.cursor_shape = cursor_shape;
 2888
 2889        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2890        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2891
 2892        cx.notify();
 2893    }
 2894
 2895    pub fn set_current_line_highlight(
 2896        &mut self,
 2897        current_line_highlight: Option<CurrentLineHighlight>,
 2898    ) {
 2899        self.current_line_highlight = current_line_highlight;
 2900    }
 2901
 2902    pub fn range_for_match<T: std::marker::Copy>(
 2903        &self,
 2904        range: &Range<T>,
 2905        collapse: bool,
 2906    ) -> Range<T> {
 2907        if collapse {
 2908            return range.start..range.start;
 2909        }
 2910        range.clone()
 2911    }
 2912
 2913    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2914        if self.display_map.read(cx).clip_at_line_ends != clip {
 2915            self.display_map
 2916                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2917        }
 2918    }
 2919
 2920    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2921        self.input_enabled = input_enabled;
 2922    }
 2923
 2924    pub fn set_edit_predictions_hidden_for_vim_mode(
 2925        &mut self,
 2926        hidden: bool,
 2927        window: &mut Window,
 2928        cx: &mut Context<Self>,
 2929    ) {
 2930        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2931            self.edit_predictions_hidden_for_vim_mode = hidden;
 2932            if hidden {
 2933                self.update_visible_edit_prediction(window, cx);
 2934            } else {
 2935                self.refresh_edit_prediction(true, false, window, cx);
 2936            }
 2937        }
 2938    }
 2939
 2940    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2941        self.menu_edit_predictions_policy = value;
 2942    }
 2943
 2944    pub fn set_autoindent(&mut self, autoindent: bool) {
 2945        if autoindent {
 2946            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2947        } else {
 2948            self.autoindent_mode = None;
 2949        }
 2950    }
 2951
 2952    pub fn read_only(&self, cx: &App) -> bool {
 2953        self.read_only || self.buffer.read(cx).read_only()
 2954    }
 2955
 2956    pub fn set_read_only(&mut self, read_only: bool) {
 2957        self.read_only = read_only;
 2958    }
 2959
 2960    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2961        self.use_autoclose = autoclose;
 2962    }
 2963
 2964    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2965        self.use_auto_surround = auto_surround;
 2966    }
 2967
 2968    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2969        self.auto_replace_emoji_shortcode = auto_replace;
 2970    }
 2971
 2972    pub fn toggle_edit_predictions(
 2973        &mut self,
 2974        _: &ToggleEditPrediction,
 2975        window: &mut Window,
 2976        cx: &mut Context<Self>,
 2977    ) {
 2978        if self.show_edit_predictions_override.is_some() {
 2979            self.set_show_edit_predictions(None, window, cx);
 2980        } else {
 2981            let show_edit_predictions = !self.edit_predictions_enabled();
 2982            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2983        }
 2984    }
 2985
 2986    pub fn set_show_edit_predictions(
 2987        &mut self,
 2988        show_edit_predictions: Option<bool>,
 2989        window: &mut Window,
 2990        cx: &mut Context<Self>,
 2991    ) {
 2992        self.show_edit_predictions_override = show_edit_predictions;
 2993        self.update_edit_prediction_settings(cx);
 2994
 2995        if let Some(false) = show_edit_predictions {
 2996            self.discard_edit_prediction(false, cx);
 2997        } else {
 2998            self.refresh_edit_prediction(false, true, window, cx);
 2999        }
 3000    }
 3001
 3002    fn edit_predictions_disabled_in_scope(
 3003        &self,
 3004        buffer: &Entity<Buffer>,
 3005        buffer_position: language::Anchor,
 3006        cx: &App,
 3007    ) -> bool {
 3008        let snapshot = buffer.read(cx).snapshot();
 3009        let settings = snapshot.settings_at(buffer_position, cx);
 3010
 3011        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3012            return false;
 3013        };
 3014
 3015        scope.override_name().is_some_and(|scope_name| {
 3016            settings
 3017                .edit_predictions_disabled_in
 3018                .iter()
 3019                .any(|s| s == scope_name)
 3020        })
 3021    }
 3022
 3023    pub fn set_use_modal_editing(&mut self, to: bool) {
 3024        self.use_modal_editing = to;
 3025    }
 3026
 3027    pub fn use_modal_editing(&self) -> bool {
 3028        self.use_modal_editing
 3029    }
 3030
 3031    fn selections_did_change(
 3032        &mut self,
 3033        local: bool,
 3034        old_cursor_position: &Anchor,
 3035        effects: SelectionEffects,
 3036        window: &mut Window,
 3037        cx: &mut Context<Self>,
 3038    ) {
 3039        window.invalidate_character_coordinates();
 3040
 3041        // Copy selections to primary selection buffer
 3042        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3043        if local {
 3044            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3045            let buffer_handle = self.buffer.read(cx).read(cx);
 3046
 3047            let mut text = String::new();
 3048            for (index, selection) in selections.iter().enumerate() {
 3049                let text_for_selection = buffer_handle
 3050                    .text_for_range(selection.start..selection.end)
 3051                    .collect::<String>();
 3052
 3053                text.push_str(&text_for_selection);
 3054                if index != selections.len() - 1 {
 3055                    text.push('\n');
 3056                }
 3057            }
 3058
 3059            if !text.is_empty() {
 3060                cx.write_to_primary(ClipboardItem::new_string(text));
 3061            }
 3062        }
 3063
 3064        let selection_anchors = self.selections.disjoint_anchors_arc();
 3065
 3066        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3067            self.buffer.update(cx, |buffer, cx| {
 3068                buffer.set_active_selections(
 3069                    &selection_anchors,
 3070                    self.selections.line_mode(),
 3071                    self.cursor_shape,
 3072                    cx,
 3073                )
 3074            });
 3075        }
 3076        let display_map = self
 3077            .display_map
 3078            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3079        let buffer = display_map.buffer_snapshot();
 3080        if self.selections.count() == 1 {
 3081            self.add_selections_state = None;
 3082        }
 3083        self.select_next_state = None;
 3084        self.select_prev_state = None;
 3085        self.select_syntax_node_history.try_clear();
 3086        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3087        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3088        self.take_rename(false, window, cx);
 3089
 3090        let newest_selection = self.selections.newest_anchor();
 3091        let new_cursor_position = newest_selection.head();
 3092        let selection_start = newest_selection.start;
 3093
 3094        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3095            self.push_to_nav_history(
 3096                *old_cursor_position,
 3097                Some(new_cursor_position.to_point(buffer)),
 3098                false,
 3099                effects.nav_history == Some(true),
 3100                cx,
 3101            );
 3102        }
 3103
 3104        if local {
 3105            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3106                self.register_buffer(buffer_id, cx);
 3107            }
 3108
 3109            let mut context_menu = self.context_menu.borrow_mut();
 3110            let completion_menu = match context_menu.as_ref() {
 3111                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3112                Some(CodeContextMenu::CodeActions(_)) => {
 3113                    *context_menu = None;
 3114                    None
 3115                }
 3116                None => None,
 3117            };
 3118            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3119            drop(context_menu);
 3120
 3121            if effects.completions
 3122                && let Some(completion_position) = completion_position
 3123            {
 3124                let start_offset = selection_start.to_offset(buffer);
 3125                let position_matches = start_offset == completion_position.to_offset(buffer);
 3126                let continue_showing = if position_matches {
 3127                    if self.snippet_stack.is_empty() {
 3128                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3129                            == Some(CharKind::Word)
 3130                    } else {
 3131                        // Snippet choices can be shown even when the cursor is in whitespace.
 3132                        // Dismissing the menu with actions like backspace is handled by
 3133                        // invalidation regions.
 3134                        true
 3135                    }
 3136                } else {
 3137                    false
 3138                };
 3139
 3140                if continue_showing {
 3141                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3142                } else {
 3143                    self.hide_context_menu(window, cx);
 3144                }
 3145            }
 3146
 3147            hide_hover(self, cx);
 3148
 3149            if old_cursor_position.to_display_point(&display_map).row()
 3150                != new_cursor_position.to_display_point(&display_map).row()
 3151            {
 3152                self.available_code_actions.take();
 3153            }
 3154            self.refresh_code_actions(window, cx);
 3155            self.refresh_document_highlights(cx);
 3156            refresh_linked_ranges(self, window, cx);
 3157
 3158            self.refresh_selected_text_highlights(false, window, cx);
 3159            self.refresh_matching_bracket_highlights(window, cx);
 3160            self.update_visible_edit_prediction(window, cx);
 3161            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3162            self.inline_blame_popover.take();
 3163            if self.git_blame_inline_enabled {
 3164                self.start_inline_blame_timer(window, cx);
 3165            }
 3166        }
 3167
 3168        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3169        cx.emit(EditorEvent::SelectionsChanged { local });
 3170
 3171        let selections = &self.selections.disjoint_anchors_arc();
 3172        if selections.len() == 1 {
 3173            cx.emit(SearchEvent::ActiveMatchChanged)
 3174        }
 3175        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3176            let inmemory_selections = selections
 3177                .iter()
 3178                .map(|s| {
 3179                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3180                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3181                })
 3182                .collect();
 3183            self.update_restoration_data(cx, |data| {
 3184                data.selections = inmemory_selections;
 3185            });
 3186
 3187            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3188                && let Some(workspace_id) =
 3189                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3190            {
 3191                let snapshot = self.buffer().read(cx).snapshot(cx);
 3192                let selections = selections.clone();
 3193                let background_executor = cx.background_executor().clone();
 3194                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3195                self.serialize_selections = cx.background_spawn(async move {
 3196                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3197                    let db_selections = selections
 3198                        .iter()
 3199                        .map(|selection| {
 3200                            (
 3201                                selection.start.to_offset(&snapshot),
 3202                                selection.end.to_offset(&snapshot),
 3203                            )
 3204                        })
 3205                        .collect();
 3206
 3207                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3208                        .await
 3209                        .with_context(|| {
 3210                            format!(
 3211                                "persisting editor selections for editor {editor_id}, \
 3212                                workspace {workspace_id:?}"
 3213                            )
 3214                        })
 3215                        .log_err();
 3216                });
 3217            }
 3218        }
 3219
 3220        cx.notify();
 3221    }
 3222
 3223    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3224        use text::ToOffset as _;
 3225        use text::ToPoint as _;
 3226
 3227        if self.mode.is_minimap()
 3228            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3229        {
 3230            return;
 3231        }
 3232
 3233        if !self.buffer().read(cx).is_singleton() {
 3234            return;
 3235        }
 3236
 3237        let display_snapshot = self
 3238            .display_map
 3239            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3240        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3241            return;
 3242        };
 3243        let inmemory_folds = display_snapshot
 3244            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3245            .map(|fold| {
 3246                fold.range.start.text_anchor.to_point(&snapshot)
 3247                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3248            })
 3249            .collect();
 3250        self.update_restoration_data(cx, |data| {
 3251            data.folds = inmemory_folds;
 3252        });
 3253
 3254        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3255            return;
 3256        };
 3257        let background_executor = cx.background_executor().clone();
 3258        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3259        let db_folds = display_snapshot
 3260            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3261            .map(|fold| {
 3262                (
 3263                    fold.range.start.text_anchor.to_offset(&snapshot),
 3264                    fold.range.end.text_anchor.to_offset(&snapshot),
 3265                )
 3266            })
 3267            .collect();
 3268        self.serialize_folds = cx.background_spawn(async move {
 3269            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3270            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3271                .await
 3272                .with_context(|| {
 3273                    format!(
 3274                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3275                    )
 3276                })
 3277                .log_err();
 3278        });
 3279    }
 3280
 3281    pub fn sync_selections(
 3282        &mut self,
 3283        other: Entity<Editor>,
 3284        cx: &mut Context<Self>,
 3285    ) -> gpui::Subscription {
 3286        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3287        if !other_selections.is_empty() {
 3288            self.selections.change_with(cx, |selections| {
 3289                selections.select_anchors(other_selections);
 3290            });
 3291        }
 3292
 3293        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3294            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3295                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3296                if other_selections.is_empty() {
 3297                    return;
 3298                }
 3299                this.selections.change_with(cx, |selections| {
 3300                    selections.select_anchors(other_selections);
 3301                });
 3302            }
 3303        });
 3304
 3305        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3306            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3307                let these_selections = this.selections.disjoint_anchors().to_vec();
 3308                if these_selections.is_empty() {
 3309                    return;
 3310                }
 3311                other.update(cx, |other_editor, cx| {
 3312                    other_editor.selections.change_with(cx, |selections| {
 3313                        selections.select_anchors(these_selections);
 3314                    })
 3315                });
 3316            }
 3317        });
 3318
 3319        Subscription::join(other_subscription, this_subscription)
 3320    }
 3321
 3322    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3323    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3324    /// effects of selection change occur at the end of the transaction.
 3325    pub fn change_selections<R>(
 3326        &mut self,
 3327        effects: SelectionEffects,
 3328        window: &mut Window,
 3329        cx: &mut Context<Self>,
 3330        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3331    ) -> R {
 3332        if let Some(state) = &mut self.deferred_selection_effects_state {
 3333            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3334            state.effects.completions = effects.completions;
 3335            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3336            let (changed, result) = self.selections.change_with(cx, change);
 3337            state.changed |= changed;
 3338            return result;
 3339        }
 3340        let mut state = DeferredSelectionEffectsState {
 3341            changed: false,
 3342            effects,
 3343            old_cursor_position: self.selections.newest_anchor().head(),
 3344            history_entry: SelectionHistoryEntry {
 3345                selections: self.selections.disjoint_anchors_arc(),
 3346                select_next_state: self.select_next_state.clone(),
 3347                select_prev_state: self.select_prev_state.clone(),
 3348                add_selections_state: self.add_selections_state.clone(),
 3349            },
 3350        };
 3351        let (changed, result) = self.selections.change_with(cx, change);
 3352        state.changed = state.changed || changed;
 3353        if self.defer_selection_effects {
 3354            self.deferred_selection_effects_state = Some(state);
 3355        } else {
 3356            self.apply_selection_effects(state, window, cx);
 3357        }
 3358        result
 3359    }
 3360
 3361    /// Defers the effects of selection change, so that the effects of multiple calls to
 3362    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3363    /// to selection history and the state of popovers based on selection position aren't
 3364    /// erroneously updated.
 3365    pub fn with_selection_effects_deferred<R>(
 3366        &mut self,
 3367        window: &mut Window,
 3368        cx: &mut Context<Self>,
 3369        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3370    ) -> R {
 3371        let already_deferred = self.defer_selection_effects;
 3372        self.defer_selection_effects = true;
 3373        let result = update(self, window, cx);
 3374        if !already_deferred {
 3375            self.defer_selection_effects = false;
 3376            if let Some(state) = self.deferred_selection_effects_state.take() {
 3377                self.apply_selection_effects(state, window, cx);
 3378            }
 3379        }
 3380        result
 3381    }
 3382
 3383    fn apply_selection_effects(
 3384        &mut self,
 3385        state: DeferredSelectionEffectsState,
 3386        window: &mut Window,
 3387        cx: &mut Context<Self>,
 3388    ) {
 3389        if state.changed {
 3390            self.selection_history.push(state.history_entry);
 3391
 3392            if let Some(autoscroll) = state.effects.scroll {
 3393                self.request_autoscroll(autoscroll, cx);
 3394            }
 3395
 3396            let old_cursor_position = &state.old_cursor_position;
 3397
 3398            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3399
 3400            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3401                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3402            }
 3403        }
 3404    }
 3405
 3406    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3407    where
 3408        I: IntoIterator<Item = (Range<S>, T)>,
 3409        S: ToOffset,
 3410        T: Into<Arc<str>>,
 3411    {
 3412        if self.read_only(cx) {
 3413            return;
 3414        }
 3415
 3416        self.buffer
 3417            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3418    }
 3419
 3420    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3421    where
 3422        I: IntoIterator<Item = (Range<S>, T)>,
 3423        S: ToOffset,
 3424        T: Into<Arc<str>>,
 3425    {
 3426        if self.read_only(cx) {
 3427            return;
 3428        }
 3429
 3430        self.buffer.update(cx, |buffer, cx| {
 3431            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3432        });
 3433    }
 3434
 3435    pub fn edit_with_block_indent<I, S, T>(
 3436        &mut self,
 3437        edits: I,
 3438        original_indent_columns: Vec<Option<u32>>,
 3439        cx: &mut Context<Self>,
 3440    ) where
 3441        I: IntoIterator<Item = (Range<S>, T)>,
 3442        S: ToOffset,
 3443        T: Into<Arc<str>>,
 3444    {
 3445        if self.read_only(cx) {
 3446            return;
 3447        }
 3448
 3449        self.buffer.update(cx, |buffer, cx| {
 3450            buffer.edit(
 3451                edits,
 3452                Some(AutoindentMode::Block {
 3453                    original_indent_columns,
 3454                }),
 3455                cx,
 3456            )
 3457        });
 3458    }
 3459
 3460    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3461        self.hide_context_menu(window, cx);
 3462
 3463        match phase {
 3464            SelectPhase::Begin {
 3465                position,
 3466                add,
 3467                click_count,
 3468            } => self.begin_selection(position, add, click_count, window, cx),
 3469            SelectPhase::BeginColumnar {
 3470                position,
 3471                goal_column,
 3472                reset,
 3473                mode,
 3474            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3475            SelectPhase::Extend {
 3476                position,
 3477                click_count,
 3478            } => self.extend_selection(position, click_count, window, cx),
 3479            SelectPhase::Update {
 3480                position,
 3481                goal_column,
 3482                scroll_delta,
 3483            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3484            SelectPhase::End => self.end_selection(window, cx),
 3485        }
 3486    }
 3487
 3488    fn extend_selection(
 3489        &mut self,
 3490        position: DisplayPoint,
 3491        click_count: usize,
 3492        window: &mut Window,
 3493        cx: &mut Context<Self>,
 3494    ) {
 3495        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3496        let tail = self.selections.newest::<usize>(&display_map).tail();
 3497        let click_count = click_count.max(match self.selections.select_mode() {
 3498            SelectMode::Character => 1,
 3499            SelectMode::Word(_) => 2,
 3500            SelectMode::Line(_) => 3,
 3501            SelectMode::All => 4,
 3502        });
 3503        self.begin_selection(position, false, click_count, window, cx);
 3504
 3505        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3506
 3507        let current_selection = match self.selections.select_mode() {
 3508            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3509            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3510        };
 3511
 3512        let mut pending_selection = self
 3513            .selections
 3514            .pending_anchor()
 3515            .cloned()
 3516            .expect("extend_selection not called with pending selection");
 3517
 3518        if pending_selection
 3519            .start
 3520            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3521            == Ordering::Greater
 3522        {
 3523            pending_selection.start = current_selection.start;
 3524        }
 3525        if pending_selection
 3526            .end
 3527            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3528            == Ordering::Less
 3529        {
 3530            pending_selection.end = current_selection.end;
 3531            pending_selection.reversed = true;
 3532        }
 3533
 3534        let mut pending_mode = self.selections.pending_mode().unwrap();
 3535        match &mut pending_mode {
 3536            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3537            _ => {}
 3538        }
 3539
 3540        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3541            SelectionEffects::scroll(Autoscroll::fit())
 3542        } else {
 3543            SelectionEffects::no_scroll()
 3544        };
 3545
 3546        self.change_selections(effects, window, cx, |s| {
 3547            s.set_pending(pending_selection.clone(), pending_mode);
 3548            s.set_is_extending(true);
 3549        });
 3550    }
 3551
 3552    fn begin_selection(
 3553        &mut self,
 3554        position: DisplayPoint,
 3555        add: bool,
 3556        click_count: usize,
 3557        window: &mut Window,
 3558        cx: &mut Context<Self>,
 3559    ) {
 3560        if !self.focus_handle.is_focused(window) {
 3561            self.last_focused_descendant = None;
 3562            window.focus(&self.focus_handle);
 3563        }
 3564
 3565        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3566        let buffer = display_map.buffer_snapshot();
 3567        let position = display_map.clip_point(position, Bias::Left);
 3568
 3569        let start;
 3570        let end;
 3571        let mode;
 3572        let mut auto_scroll;
 3573        match click_count {
 3574            1 => {
 3575                start = buffer.anchor_before(position.to_point(&display_map));
 3576                end = start;
 3577                mode = SelectMode::Character;
 3578                auto_scroll = true;
 3579            }
 3580            2 => {
 3581                let position = display_map
 3582                    .clip_point(position, Bias::Left)
 3583                    .to_offset(&display_map, Bias::Left);
 3584                let (range, _) = buffer.surrounding_word(position, None);
 3585                start = buffer.anchor_before(range.start);
 3586                end = buffer.anchor_before(range.end);
 3587                mode = SelectMode::Word(start..end);
 3588                auto_scroll = true;
 3589            }
 3590            3 => {
 3591                let position = display_map
 3592                    .clip_point(position, Bias::Left)
 3593                    .to_point(&display_map);
 3594                let line_start = display_map.prev_line_boundary(position).0;
 3595                let next_line_start = buffer.clip_point(
 3596                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3597                    Bias::Left,
 3598                );
 3599                start = buffer.anchor_before(line_start);
 3600                end = buffer.anchor_before(next_line_start);
 3601                mode = SelectMode::Line(start..end);
 3602                auto_scroll = true;
 3603            }
 3604            _ => {
 3605                start = buffer.anchor_before(0);
 3606                end = buffer.anchor_before(buffer.len());
 3607                mode = SelectMode::All;
 3608                auto_scroll = false;
 3609            }
 3610        }
 3611        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3612
 3613        let point_to_delete: Option<usize> = {
 3614            let selected_points: Vec<Selection<Point>> =
 3615                self.selections.disjoint_in_range(start..end, &display_map);
 3616
 3617            if !add || click_count > 1 {
 3618                None
 3619            } else if !selected_points.is_empty() {
 3620                Some(selected_points[0].id)
 3621            } else {
 3622                let clicked_point_already_selected =
 3623                    self.selections.disjoint_anchors().iter().find(|selection| {
 3624                        selection.start.to_point(buffer) == start.to_point(buffer)
 3625                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3626                    });
 3627
 3628                clicked_point_already_selected.map(|selection| selection.id)
 3629            }
 3630        };
 3631
 3632        let selections_count = self.selections.count();
 3633        let effects = if auto_scroll {
 3634            SelectionEffects::default()
 3635        } else {
 3636            SelectionEffects::no_scroll()
 3637        };
 3638
 3639        self.change_selections(effects, window, cx, |s| {
 3640            if let Some(point_to_delete) = point_to_delete {
 3641                s.delete(point_to_delete);
 3642
 3643                if selections_count == 1 {
 3644                    s.set_pending_anchor_range(start..end, mode);
 3645                }
 3646            } else {
 3647                if !add {
 3648                    s.clear_disjoint();
 3649                }
 3650
 3651                s.set_pending_anchor_range(start..end, mode);
 3652            }
 3653        });
 3654    }
 3655
 3656    fn begin_columnar_selection(
 3657        &mut self,
 3658        position: DisplayPoint,
 3659        goal_column: u32,
 3660        reset: bool,
 3661        mode: ColumnarMode,
 3662        window: &mut Window,
 3663        cx: &mut Context<Self>,
 3664    ) {
 3665        if !self.focus_handle.is_focused(window) {
 3666            self.last_focused_descendant = None;
 3667            window.focus(&self.focus_handle);
 3668        }
 3669
 3670        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3671
 3672        if reset {
 3673            let pointer_position = display_map
 3674                .buffer_snapshot()
 3675                .anchor_before(position.to_point(&display_map));
 3676
 3677            self.change_selections(
 3678                SelectionEffects::scroll(Autoscroll::newest()),
 3679                window,
 3680                cx,
 3681                |s| {
 3682                    s.clear_disjoint();
 3683                    s.set_pending_anchor_range(
 3684                        pointer_position..pointer_position,
 3685                        SelectMode::Character,
 3686                    );
 3687                },
 3688            );
 3689        };
 3690
 3691        let tail = self.selections.newest::<Point>(&display_map).tail();
 3692        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3693        self.columnar_selection_state = match mode {
 3694            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3695                selection_tail: selection_anchor,
 3696                display_point: if reset {
 3697                    if position.column() != goal_column {
 3698                        Some(DisplayPoint::new(position.row(), goal_column))
 3699                    } else {
 3700                        None
 3701                    }
 3702                } else {
 3703                    None
 3704                },
 3705            }),
 3706            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3707                selection_tail: selection_anchor,
 3708            }),
 3709        };
 3710
 3711        if !reset {
 3712            self.select_columns(position, goal_column, &display_map, window, cx);
 3713        }
 3714    }
 3715
 3716    fn update_selection(
 3717        &mut self,
 3718        position: DisplayPoint,
 3719        goal_column: u32,
 3720        scroll_delta: gpui::Point<f32>,
 3721        window: &mut Window,
 3722        cx: &mut Context<Self>,
 3723    ) {
 3724        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3725
 3726        if self.columnar_selection_state.is_some() {
 3727            self.select_columns(position, goal_column, &display_map, window, cx);
 3728        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3729            let buffer = display_map.buffer_snapshot();
 3730            let head;
 3731            let tail;
 3732            let mode = self.selections.pending_mode().unwrap();
 3733            match &mode {
 3734                SelectMode::Character => {
 3735                    head = position.to_point(&display_map);
 3736                    tail = pending.tail().to_point(buffer);
 3737                }
 3738                SelectMode::Word(original_range) => {
 3739                    let offset = display_map
 3740                        .clip_point(position, Bias::Left)
 3741                        .to_offset(&display_map, Bias::Left);
 3742                    let original_range = original_range.to_offset(buffer);
 3743
 3744                    let head_offset = if buffer.is_inside_word(offset, None)
 3745                        || original_range.contains(&offset)
 3746                    {
 3747                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3748                        if word_range.start < original_range.start {
 3749                            word_range.start
 3750                        } else {
 3751                            word_range.end
 3752                        }
 3753                    } else {
 3754                        offset
 3755                    };
 3756
 3757                    head = head_offset.to_point(buffer);
 3758                    if head_offset <= original_range.start {
 3759                        tail = original_range.end.to_point(buffer);
 3760                    } else {
 3761                        tail = original_range.start.to_point(buffer);
 3762                    }
 3763                }
 3764                SelectMode::Line(original_range) => {
 3765                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3766
 3767                    let position = display_map
 3768                        .clip_point(position, Bias::Left)
 3769                        .to_point(&display_map);
 3770                    let line_start = display_map.prev_line_boundary(position).0;
 3771                    let next_line_start = buffer.clip_point(
 3772                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3773                        Bias::Left,
 3774                    );
 3775
 3776                    if line_start < original_range.start {
 3777                        head = line_start
 3778                    } else {
 3779                        head = next_line_start
 3780                    }
 3781
 3782                    if head <= original_range.start {
 3783                        tail = original_range.end;
 3784                    } else {
 3785                        tail = original_range.start;
 3786                    }
 3787                }
 3788                SelectMode::All => {
 3789                    return;
 3790                }
 3791            };
 3792
 3793            if head < tail {
 3794                pending.start = buffer.anchor_before(head);
 3795                pending.end = buffer.anchor_before(tail);
 3796                pending.reversed = true;
 3797            } else {
 3798                pending.start = buffer.anchor_before(tail);
 3799                pending.end = buffer.anchor_before(head);
 3800                pending.reversed = false;
 3801            }
 3802
 3803            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3804                s.set_pending(pending.clone(), mode);
 3805            });
 3806        } else {
 3807            log::error!("update_selection dispatched with no pending selection");
 3808            return;
 3809        }
 3810
 3811        self.apply_scroll_delta(scroll_delta, window, cx);
 3812        cx.notify();
 3813    }
 3814
 3815    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3816        self.columnar_selection_state.take();
 3817        if let Some(pending_mode) = self.selections.pending_mode() {
 3818            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3819            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3820                s.select(selections);
 3821                s.clear_pending();
 3822                if s.is_extending() {
 3823                    s.set_is_extending(false);
 3824                } else {
 3825                    s.set_select_mode(pending_mode);
 3826                }
 3827            });
 3828        }
 3829    }
 3830
 3831    fn select_columns(
 3832        &mut self,
 3833        head: DisplayPoint,
 3834        goal_column: u32,
 3835        display_map: &DisplaySnapshot,
 3836        window: &mut Window,
 3837        cx: &mut Context<Self>,
 3838    ) {
 3839        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3840            return;
 3841        };
 3842
 3843        let tail = match columnar_state {
 3844            ColumnarSelectionState::FromMouse {
 3845                selection_tail,
 3846                display_point,
 3847            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3848            ColumnarSelectionState::FromSelection { selection_tail } => {
 3849                selection_tail.to_display_point(display_map)
 3850            }
 3851        };
 3852
 3853        let start_row = cmp::min(tail.row(), head.row());
 3854        let end_row = cmp::max(tail.row(), head.row());
 3855        let start_column = cmp::min(tail.column(), goal_column);
 3856        let end_column = cmp::max(tail.column(), goal_column);
 3857        let reversed = start_column < tail.column();
 3858
 3859        let selection_ranges = (start_row.0..=end_row.0)
 3860            .map(DisplayRow)
 3861            .filter_map(|row| {
 3862                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3863                    || start_column <= display_map.line_len(row))
 3864                    && !display_map.is_block_line(row)
 3865                {
 3866                    let start = display_map
 3867                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3868                        .to_point(display_map);
 3869                    let end = display_map
 3870                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3871                        .to_point(display_map);
 3872                    if reversed {
 3873                        Some(end..start)
 3874                    } else {
 3875                        Some(start..end)
 3876                    }
 3877                } else {
 3878                    None
 3879                }
 3880            })
 3881            .collect::<Vec<_>>();
 3882        if selection_ranges.is_empty() {
 3883            return;
 3884        }
 3885
 3886        let ranges = match columnar_state {
 3887            ColumnarSelectionState::FromMouse { .. } => {
 3888                let mut non_empty_ranges = selection_ranges
 3889                    .iter()
 3890                    .filter(|selection_range| selection_range.start != selection_range.end)
 3891                    .peekable();
 3892                if non_empty_ranges.peek().is_some() {
 3893                    non_empty_ranges.cloned().collect()
 3894                } else {
 3895                    selection_ranges
 3896                }
 3897            }
 3898            _ => selection_ranges,
 3899        };
 3900
 3901        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3902            s.select_ranges(ranges);
 3903        });
 3904        cx.notify();
 3905    }
 3906
 3907    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3908        self.selections
 3909            .all_adjusted(snapshot)
 3910            .iter()
 3911            .any(|selection| !selection.is_empty())
 3912    }
 3913
 3914    pub fn has_pending_nonempty_selection(&self) -> bool {
 3915        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3916            Some(Selection { start, end, .. }) => start != end,
 3917            None => false,
 3918        };
 3919
 3920        pending_nonempty_selection
 3921            || (self.columnar_selection_state.is_some()
 3922                && self.selections.disjoint_anchors().len() > 1)
 3923    }
 3924
 3925    pub fn has_pending_selection(&self) -> bool {
 3926        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3927    }
 3928
 3929    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3930        self.selection_mark_mode = false;
 3931        self.selection_drag_state = SelectionDragState::None;
 3932
 3933        if self.clear_expanded_diff_hunks(cx) {
 3934            cx.notify();
 3935            return;
 3936        }
 3937        if self.dismiss_menus_and_popups(true, window, cx) {
 3938            return;
 3939        }
 3940
 3941        if self.mode.is_full()
 3942            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3943        {
 3944            return;
 3945        }
 3946
 3947        cx.propagate();
 3948    }
 3949
 3950    pub fn dismiss_menus_and_popups(
 3951        &mut self,
 3952        is_user_requested: bool,
 3953        window: &mut Window,
 3954        cx: &mut Context<Self>,
 3955    ) -> bool {
 3956        if self.take_rename(false, window, cx).is_some() {
 3957            return true;
 3958        }
 3959
 3960        if self.hide_blame_popover(true, cx) {
 3961            return true;
 3962        }
 3963
 3964        if hide_hover(self, cx) {
 3965            return true;
 3966        }
 3967
 3968        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3969            return true;
 3970        }
 3971
 3972        if self.hide_context_menu(window, cx).is_some() {
 3973            return true;
 3974        }
 3975
 3976        if self.mouse_context_menu.take().is_some() {
 3977            return true;
 3978        }
 3979
 3980        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3981            return true;
 3982        }
 3983
 3984        if self.snippet_stack.pop().is_some() {
 3985            return true;
 3986        }
 3987
 3988        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3989            self.dismiss_diagnostics(cx);
 3990            return true;
 3991        }
 3992
 3993        false
 3994    }
 3995
 3996    fn linked_editing_ranges_for(
 3997        &self,
 3998        selection: Range<text::Anchor>,
 3999        cx: &App,
 4000    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4001        if self.linked_edit_ranges.is_empty() {
 4002            return None;
 4003        }
 4004        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4005            selection.end.buffer_id.and_then(|end_buffer_id| {
 4006                if selection.start.buffer_id != Some(end_buffer_id) {
 4007                    return None;
 4008                }
 4009                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4010                let snapshot = buffer.read(cx).snapshot();
 4011                self.linked_edit_ranges
 4012                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4013                    .map(|ranges| (ranges, snapshot, buffer))
 4014            })?;
 4015        use text::ToOffset as TO;
 4016        // find offset from the start of current range to current cursor position
 4017        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4018
 4019        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4020        let start_difference = start_offset - start_byte_offset;
 4021        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4022        let end_difference = end_offset - start_byte_offset;
 4023        // Current range has associated linked ranges.
 4024        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4025        for range in linked_ranges.iter() {
 4026            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4027            let end_offset = start_offset + end_difference;
 4028            let start_offset = start_offset + start_difference;
 4029            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4030                continue;
 4031            }
 4032            if self.selections.disjoint_anchor_ranges().any(|s| {
 4033                if s.start.buffer_id != selection.start.buffer_id
 4034                    || s.end.buffer_id != selection.end.buffer_id
 4035                {
 4036                    return false;
 4037                }
 4038                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4039                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4040            }) {
 4041                continue;
 4042            }
 4043            let start = buffer_snapshot.anchor_after(start_offset);
 4044            let end = buffer_snapshot.anchor_after(end_offset);
 4045            linked_edits
 4046                .entry(buffer.clone())
 4047                .or_default()
 4048                .push(start..end);
 4049        }
 4050        Some(linked_edits)
 4051    }
 4052
 4053    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4054        let text: Arc<str> = text.into();
 4055
 4056        if self.read_only(cx) {
 4057            return;
 4058        }
 4059
 4060        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4061
 4062        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4063        let mut bracket_inserted = false;
 4064        let mut edits = Vec::new();
 4065        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4066        let mut new_selections = Vec::with_capacity(selections.len());
 4067        let mut new_autoclose_regions = Vec::new();
 4068        let snapshot = self.buffer.read(cx).read(cx);
 4069        let mut clear_linked_edit_ranges = false;
 4070
 4071        for (selection, autoclose_region) in
 4072            self.selections_with_autoclose_regions(selections, &snapshot)
 4073        {
 4074            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4075                // Determine if the inserted text matches the opening or closing
 4076                // bracket of any of this language's bracket pairs.
 4077                let mut bracket_pair = None;
 4078                let mut is_bracket_pair_start = false;
 4079                let mut is_bracket_pair_end = false;
 4080                if !text.is_empty() {
 4081                    let mut bracket_pair_matching_end = None;
 4082                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4083                    //  and they are removing the character that triggered IME popup.
 4084                    for (pair, enabled) in scope.brackets() {
 4085                        if !pair.close && !pair.surround {
 4086                            continue;
 4087                        }
 4088
 4089                        if enabled && pair.start.ends_with(text.as_ref()) {
 4090                            let prefix_len = pair.start.len() - text.len();
 4091                            let preceding_text_matches_prefix = prefix_len == 0
 4092                                || (selection.start.column >= (prefix_len as u32)
 4093                                    && snapshot.contains_str_at(
 4094                                        Point::new(
 4095                                            selection.start.row,
 4096                                            selection.start.column - (prefix_len as u32),
 4097                                        ),
 4098                                        &pair.start[..prefix_len],
 4099                                    ));
 4100                            if preceding_text_matches_prefix {
 4101                                bracket_pair = Some(pair.clone());
 4102                                is_bracket_pair_start = true;
 4103                                break;
 4104                            }
 4105                        }
 4106                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4107                        {
 4108                            // take first bracket pair matching end, but don't break in case a later bracket
 4109                            // pair matches start
 4110                            bracket_pair_matching_end = Some(pair.clone());
 4111                        }
 4112                    }
 4113                    if let Some(end) = bracket_pair_matching_end
 4114                        && bracket_pair.is_none()
 4115                    {
 4116                        bracket_pair = Some(end);
 4117                        is_bracket_pair_end = true;
 4118                    }
 4119                }
 4120
 4121                if let Some(bracket_pair) = bracket_pair {
 4122                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4123                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4124                    let auto_surround =
 4125                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4126                    if selection.is_empty() {
 4127                        if is_bracket_pair_start {
 4128                            // If the inserted text is a suffix of an opening bracket and the
 4129                            // selection is preceded by the rest of the opening bracket, then
 4130                            // insert the closing bracket.
 4131                            let following_text_allows_autoclose = snapshot
 4132                                .chars_at(selection.start)
 4133                                .next()
 4134                                .is_none_or(|c| scope.should_autoclose_before(c));
 4135
 4136                            let preceding_text_allows_autoclose = selection.start.column == 0
 4137                                || snapshot
 4138                                    .reversed_chars_at(selection.start)
 4139                                    .next()
 4140                                    .is_none_or(|c| {
 4141                                        bracket_pair.start != bracket_pair.end
 4142                                            || !snapshot
 4143                                                .char_classifier_at(selection.start)
 4144                                                .is_word(c)
 4145                                    });
 4146
 4147                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4148                                && bracket_pair.start.len() == 1
 4149                            {
 4150                                let target = bracket_pair.start.chars().next().unwrap();
 4151                                let current_line_count = snapshot
 4152                                    .reversed_chars_at(selection.start)
 4153                                    .take_while(|&c| c != '\n')
 4154                                    .filter(|&c| c == target)
 4155                                    .count();
 4156                                current_line_count % 2 == 1
 4157                            } else {
 4158                                false
 4159                            };
 4160
 4161                            if autoclose
 4162                                && bracket_pair.close
 4163                                && following_text_allows_autoclose
 4164                                && preceding_text_allows_autoclose
 4165                                && !is_closing_quote
 4166                            {
 4167                                let anchor = snapshot.anchor_before(selection.end);
 4168                                new_selections.push((selection.map(|_| anchor), text.len()));
 4169                                new_autoclose_regions.push((
 4170                                    anchor,
 4171                                    text.len(),
 4172                                    selection.id,
 4173                                    bracket_pair.clone(),
 4174                                ));
 4175                                edits.push((
 4176                                    selection.range(),
 4177                                    format!("{}{}", text, bracket_pair.end).into(),
 4178                                ));
 4179                                bracket_inserted = true;
 4180                                continue;
 4181                            }
 4182                        }
 4183
 4184                        if let Some(region) = autoclose_region {
 4185                            // If the selection is followed by an auto-inserted closing bracket,
 4186                            // then don't insert that closing bracket again; just move the selection
 4187                            // past the closing bracket.
 4188                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4189                                && text.as_ref() == region.pair.end.as_str()
 4190                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4191                            if should_skip {
 4192                                let anchor = snapshot.anchor_after(selection.end);
 4193                                new_selections
 4194                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4195                                continue;
 4196                            }
 4197                        }
 4198
 4199                        let always_treat_brackets_as_autoclosed = snapshot
 4200                            .language_settings_at(selection.start, cx)
 4201                            .always_treat_brackets_as_autoclosed;
 4202                        if always_treat_brackets_as_autoclosed
 4203                            && is_bracket_pair_end
 4204                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4205                        {
 4206                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4207                            // and the inserted text is a closing bracket and the selection is followed
 4208                            // by the closing bracket then move the selection past the closing bracket.
 4209                            let anchor = snapshot.anchor_after(selection.end);
 4210                            new_selections.push((selection.map(|_| anchor), text.len()));
 4211                            continue;
 4212                        }
 4213                    }
 4214                    // If an opening bracket is 1 character long and is typed while
 4215                    // text is selected, then surround that text with the bracket pair.
 4216                    else if auto_surround
 4217                        && bracket_pair.surround
 4218                        && is_bracket_pair_start
 4219                        && bracket_pair.start.chars().count() == 1
 4220                    {
 4221                        edits.push((selection.start..selection.start, text.clone()));
 4222                        edits.push((
 4223                            selection.end..selection.end,
 4224                            bracket_pair.end.as_str().into(),
 4225                        ));
 4226                        bracket_inserted = true;
 4227                        new_selections.push((
 4228                            Selection {
 4229                                id: selection.id,
 4230                                start: snapshot.anchor_after(selection.start),
 4231                                end: snapshot.anchor_before(selection.end),
 4232                                reversed: selection.reversed,
 4233                                goal: selection.goal,
 4234                            },
 4235                            0,
 4236                        ));
 4237                        continue;
 4238                    }
 4239                }
 4240            }
 4241
 4242            if self.auto_replace_emoji_shortcode
 4243                && selection.is_empty()
 4244                && text.as_ref().ends_with(':')
 4245                && let Some(possible_emoji_short_code) =
 4246                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4247                && !possible_emoji_short_code.is_empty()
 4248                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4249            {
 4250                let emoji_shortcode_start = Point::new(
 4251                    selection.start.row,
 4252                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4253                );
 4254
 4255                // Remove shortcode from buffer
 4256                edits.push((
 4257                    emoji_shortcode_start..selection.start,
 4258                    "".to_string().into(),
 4259                ));
 4260                new_selections.push((
 4261                    Selection {
 4262                        id: selection.id,
 4263                        start: snapshot.anchor_after(emoji_shortcode_start),
 4264                        end: snapshot.anchor_before(selection.start),
 4265                        reversed: selection.reversed,
 4266                        goal: selection.goal,
 4267                    },
 4268                    0,
 4269                ));
 4270
 4271                // Insert emoji
 4272                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4273                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4274                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4275
 4276                continue;
 4277            }
 4278
 4279            // If not handling any auto-close operation, then just replace the selected
 4280            // text with the given input and move the selection to the end of the
 4281            // newly inserted text.
 4282            let anchor = snapshot.anchor_after(selection.end);
 4283            if !self.linked_edit_ranges.is_empty() {
 4284                let start_anchor = snapshot.anchor_before(selection.start);
 4285
 4286                let is_word_char = text.chars().next().is_none_or(|char| {
 4287                    let classifier = snapshot
 4288                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4289                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4290                    classifier.is_word(char)
 4291                });
 4292
 4293                if is_word_char {
 4294                    if let Some(ranges) = self
 4295                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4296                    {
 4297                        for (buffer, edits) in ranges {
 4298                            linked_edits
 4299                                .entry(buffer.clone())
 4300                                .or_default()
 4301                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4302                        }
 4303                    }
 4304                } else {
 4305                    clear_linked_edit_ranges = true;
 4306                }
 4307            }
 4308
 4309            new_selections.push((selection.map(|_| anchor), 0));
 4310            edits.push((selection.start..selection.end, text.clone()));
 4311        }
 4312
 4313        drop(snapshot);
 4314
 4315        self.transact(window, cx, |this, window, cx| {
 4316            if clear_linked_edit_ranges {
 4317                this.linked_edit_ranges.clear();
 4318            }
 4319            let initial_buffer_versions =
 4320                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4321
 4322            this.buffer.update(cx, |buffer, cx| {
 4323                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4324            });
 4325            for (buffer, edits) in linked_edits {
 4326                buffer.update(cx, |buffer, cx| {
 4327                    let snapshot = buffer.snapshot();
 4328                    let edits = edits
 4329                        .into_iter()
 4330                        .map(|(range, text)| {
 4331                            use text::ToPoint as TP;
 4332                            let end_point = TP::to_point(&range.end, &snapshot);
 4333                            let start_point = TP::to_point(&range.start, &snapshot);
 4334                            (start_point..end_point, text)
 4335                        })
 4336                        .sorted_by_key(|(range, _)| range.start);
 4337                    buffer.edit(edits, None, cx);
 4338                })
 4339            }
 4340            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4341            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4342            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4343            let new_selections =
 4344                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4345                    .zip(new_selection_deltas)
 4346                    .map(|(selection, delta)| Selection {
 4347                        id: selection.id,
 4348                        start: selection.start + delta,
 4349                        end: selection.end + delta,
 4350                        reversed: selection.reversed,
 4351                        goal: SelectionGoal::None,
 4352                    })
 4353                    .collect::<Vec<_>>();
 4354
 4355            let mut i = 0;
 4356            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4357                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4358                let start = map.buffer_snapshot().anchor_before(position);
 4359                let end = map.buffer_snapshot().anchor_after(position);
 4360                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4361                    match existing_state
 4362                        .range
 4363                        .start
 4364                        .cmp(&start, map.buffer_snapshot())
 4365                    {
 4366                        Ordering::Less => i += 1,
 4367                        Ordering::Greater => break,
 4368                        Ordering::Equal => {
 4369                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4370                                Ordering::Less => i += 1,
 4371                                Ordering::Equal => break,
 4372                                Ordering::Greater => break,
 4373                            }
 4374                        }
 4375                    }
 4376                }
 4377                this.autoclose_regions.insert(
 4378                    i,
 4379                    AutocloseRegion {
 4380                        selection_id,
 4381                        range: start..end,
 4382                        pair,
 4383                    },
 4384                );
 4385            }
 4386
 4387            let had_active_edit_prediction = this.has_active_edit_prediction();
 4388            this.change_selections(
 4389                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4390                window,
 4391                cx,
 4392                |s| s.select(new_selections),
 4393            );
 4394
 4395            if !bracket_inserted
 4396                && let Some(on_type_format_task) =
 4397                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4398            {
 4399                on_type_format_task.detach_and_log_err(cx);
 4400            }
 4401
 4402            let editor_settings = EditorSettings::get_global(cx);
 4403            if bracket_inserted
 4404                && (editor_settings.auto_signature_help
 4405                    || editor_settings.show_signature_help_after_edits)
 4406            {
 4407                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4408            }
 4409
 4410            let trigger_in_words =
 4411                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4412            if this.hard_wrap.is_some() {
 4413                let latest: Range<Point> = this.selections.newest(&map).range();
 4414                if latest.is_empty()
 4415                    && this
 4416                        .buffer()
 4417                        .read(cx)
 4418                        .snapshot(cx)
 4419                        .line_len(MultiBufferRow(latest.start.row))
 4420                        == latest.start.column
 4421                {
 4422                    this.rewrap_impl(
 4423                        RewrapOptions {
 4424                            override_language_settings: true,
 4425                            preserve_existing_whitespace: true,
 4426                        },
 4427                        cx,
 4428                    )
 4429                }
 4430            }
 4431            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4432            refresh_linked_ranges(this, window, cx);
 4433            this.refresh_edit_prediction(true, false, window, cx);
 4434            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4435        });
 4436    }
 4437
 4438    fn find_possible_emoji_shortcode_at_position(
 4439        snapshot: &MultiBufferSnapshot,
 4440        position: Point,
 4441    ) -> Option<String> {
 4442        let mut chars = Vec::new();
 4443        let mut found_colon = false;
 4444        for char in snapshot.reversed_chars_at(position).take(100) {
 4445            // Found a possible emoji shortcode in the middle of the buffer
 4446            if found_colon {
 4447                if char.is_whitespace() {
 4448                    chars.reverse();
 4449                    return Some(chars.iter().collect());
 4450                }
 4451                // If the previous character is not a whitespace, we are in the middle of a word
 4452                // and we only want to complete the shortcode if the word is made up of other emojis
 4453                let mut containing_word = String::new();
 4454                for ch in snapshot
 4455                    .reversed_chars_at(position)
 4456                    .skip(chars.len() + 1)
 4457                    .take(100)
 4458                {
 4459                    if ch.is_whitespace() {
 4460                        break;
 4461                    }
 4462                    containing_word.push(ch);
 4463                }
 4464                let containing_word = containing_word.chars().rev().collect::<String>();
 4465                if util::word_consists_of_emojis(containing_word.as_str()) {
 4466                    chars.reverse();
 4467                    return Some(chars.iter().collect());
 4468                }
 4469            }
 4470
 4471            if char.is_whitespace() || !char.is_ascii() {
 4472                return None;
 4473            }
 4474            if char == ':' {
 4475                found_colon = true;
 4476            } else {
 4477                chars.push(char);
 4478            }
 4479        }
 4480        // Found a possible emoji shortcode at the beginning of the buffer
 4481        chars.reverse();
 4482        Some(chars.iter().collect())
 4483    }
 4484
 4485    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4486        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4487        self.transact(window, cx, |this, window, cx| {
 4488            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4489                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4490                let multi_buffer = this.buffer.read(cx);
 4491                let buffer = multi_buffer.snapshot(cx);
 4492                selections
 4493                    .iter()
 4494                    .map(|selection| {
 4495                        let start_point = selection.start.to_point(&buffer);
 4496                        let mut existing_indent =
 4497                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4498                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4499                        let start = selection.start;
 4500                        let end = selection.end;
 4501                        let selection_is_empty = start == end;
 4502                        let language_scope = buffer.language_scope_at(start);
 4503                        let (
 4504                            comment_delimiter,
 4505                            doc_delimiter,
 4506                            insert_extra_newline,
 4507                            indent_on_newline,
 4508                            indent_on_extra_newline,
 4509                        ) = if let Some(language) = &language_scope {
 4510                            let mut insert_extra_newline =
 4511                                insert_extra_newline_brackets(&buffer, start..end, language)
 4512                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4513
 4514                            // Comment extension on newline is allowed only for cursor selections
 4515                            let comment_delimiter = maybe!({
 4516                                if !selection_is_empty {
 4517                                    return None;
 4518                                }
 4519
 4520                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4521                                    return None;
 4522                                }
 4523
 4524                                let delimiters = language.line_comment_prefixes();
 4525                                let max_len_of_delimiter =
 4526                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4527                                let (snapshot, range) =
 4528                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4529
 4530                                let num_of_whitespaces = snapshot
 4531                                    .chars_for_range(range.clone())
 4532                                    .take_while(|c| c.is_whitespace())
 4533                                    .count();
 4534                                let comment_candidate = snapshot
 4535                                    .chars_for_range(range.clone())
 4536                                    .skip(num_of_whitespaces)
 4537                                    .take(max_len_of_delimiter)
 4538                                    .collect::<String>();
 4539                                let (delimiter, trimmed_len) = delimiters
 4540                                    .iter()
 4541                                    .filter_map(|delimiter| {
 4542                                        let prefix = delimiter.trim_end();
 4543                                        if comment_candidate.starts_with(prefix) {
 4544                                            Some((delimiter, prefix.len()))
 4545                                        } else {
 4546                                            None
 4547                                        }
 4548                                    })
 4549                                    .max_by_key(|(_, len)| *len)?;
 4550
 4551                                if let Some(BlockCommentConfig {
 4552                                    start: block_start, ..
 4553                                }) = language.block_comment()
 4554                                {
 4555                                    let block_start_trimmed = block_start.trim_end();
 4556                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4557                                        let line_content = snapshot
 4558                                            .chars_for_range(range)
 4559                                            .skip(num_of_whitespaces)
 4560                                            .take(block_start_trimmed.len())
 4561                                            .collect::<String>();
 4562
 4563                                        if line_content.starts_with(block_start_trimmed) {
 4564                                            return None;
 4565                                        }
 4566                                    }
 4567                                }
 4568
 4569                                let cursor_is_placed_after_comment_marker =
 4570                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4571                                if cursor_is_placed_after_comment_marker {
 4572                                    Some(delimiter.clone())
 4573                                } else {
 4574                                    None
 4575                                }
 4576                            });
 4577
 4578                            let mut indent_on_newline = IndentSize::spaces(0);
 4579                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4580
 4581                            let doc_delimiter = maybe!({
 4582                                if !selection_is_empty {
 4583                                    return None;
 4584                                }
 4585
 4586                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4587                                    return None;
 4588                                }
 4589
 4590                                let BlockCommentConfig {
 4591                                    start: start_tag,
 4592                                    end: end_tag,
 4593                                    prefix: delimiter,
 4594                                    tab_size: len,
 4595                                } = language.documentation_comment()?;
 4596                                let is_within_block_comment = buffer
 4597                                    .language_scope_at(start_point)
 4598                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4599                                if !is_within_block_comment {
 4600                                    return None;
 4601                                }
 4602
 4603                                let (snapshot, range) =
 4604                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4605
 4606                                let num_of_whitespaces = snapshot
 4607                                    .chars_for_range(range.clone())
 4608                                    .take_while(|c| c.is_whitespace())
 4609                                    .count();
 4610
 4611                                // 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.
 4612                                let column = start_point.column;
 4613                                let cursor_is_after_start_tag = {
 4614                                    let start_tag_len = start_tag.len();
 4615                                    let start_tag_line = snapshot
 4616                                        .chars_for_range(range.clone())
 4617                                        .skip(num_of_whitespaces)
 4618                                        .take(start_tag_len)
 4619                                        .collect::<String>();
 4620                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4621                                        num_of_whitespaces + start_tag_len <= column as usize
 4622                                    } else {
 4623                                        false
 4624                                    }
 4625                                };
 4626
 4627                                let cursor_is_after_delimiter = {
 4628                                    let delimiter_trim = delimiter.trim_end();
 4629                                    let delimiter_line = snapshot
 4630                                        .chars_for_range(range.clone())
 4631                                        .skip(num_of_whitespaces)
 4632                                        .take(delimiter_trim.len())
 4633                                        .collect::<String>();
 4634                                    if delimiter_line.starts_with(delimiter_trim) {
 4635                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4636                                    } else {
 4637                                        false
 4638                                    }
 4639                                };
 4640
 4641                                let cursor_is_before_end_tag_if_exists = {
 4642                                    let mut char_position = 0u32;
 4643                                    let mut end_tag_offset = None;
 4644
 4645                                    'outer: for chunk in snapshot.text_for_range(range) {
 4646                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4647                                            let chars_before_match =
 4648                                                chunk[..byte_pos].chars().count() as u32;
 4649                                            end_tag_offset =
 4650                                                Some(char_position + chars_before_match);
 4651                                            break 'outer;
 4652                                        }
 4653                                        char_position += chunk.chars().count() as u32;
 4654                                    }
 4655
 4656                                    if let Some(end_tag_offset) = end_tag_offset {
 4657                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4658                                        if cursor_is_after_start_tag {
 4659                                            if cursor_is_before_end_tag {
 4660                                                insert_extra_newline = true;
 4661                                            }
 4662                                            let cursor_is_at_start_of_end_tag =
 4663                                                column == end_tag_offset;
 4664                                            if cursor_is_at_start_of_end_tag {
 4665                                                indent_on_extra_newline.len = *len;
 4666                                            }
 4667                                        }
 4668                                        cursor_is_before_end_tag
 4669                                    } else {
 4670                                        true
 4671                                    }
 4672                                };
 4673
 4674                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4675                                    && cursor_is_before_end_tag_if_exists
 4676                                {
 4677                                    if cursor_is_after_start_tag {
 4678                                        indent_on_newline.len = *len;
 4679                                    }
 4680                                    Some(delimiter.clone())
 4681                                } else {
 4682                                    None
 4683                                }
 4684                            });
 4685
 4686                            (
 4687                                comment_delimiter,
 4688                                doc_delimiter,
 4689                                insert_extra_newline,
 4690                                indent_on_newline,
 4691                                indent_on_extra_newline,
 4692                            )
 4693                        } else {
 4694                            (
 4695                                None,
 4696                                None,
 4697                                false,
 4698                                IndentSize::default(),
 4699                                IndentSize::default(),
 4700                            )
 4701                        };
 4702
 4703                        let prevent_auto_indent = doc_delimiter.is_some();
 4704                        let delimiter = comment_delimiter.or(doc_delimiter);
 4705
 4706                        let capacity_for_delimiter =
 4707                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4708                        let mut new_text = String::with_capacity(
 4709                            1 + capacity_for_delimiter
 4710                                + existing_indent.len as usize
 4711                                + indent_on_newline.len as usize
 4712                                + indent_on_extra_newline.len as usize,
 4713                        );
 4714                        new_text.push('\n');
 4715                        new_text.extend(existing_indent.chars());
 4716                        new_text.extend(indent_on_newline.chars());
 4717
 4718                        if let Some(delimiter) = &delimiter {
 4719                            new_text.push_str(delimiter);
 4720                        }
 4721
 4722                        if insert_extra_newline {
 4723                            new_text.push('\n');
 4724                            new_text.extend(existing_indent.chars());
 4725                            new_text.extend(indent_on_extra_newline.chars());
 4726                        }
 4727
 4728                        let anchor = buffer.anchor_after(end);
 4729                        let new_selection = selection.map(|_| anchor);
 4730                        (
 4731                            ((start..end, new_text), prevent_auto_indent),
 4732                            (insert_extra_newline, new_selection),
 4733                        )
 4734                    })
 4735                    .unzip()
 4736            };
 4737
 4738            let mut auto_indent_edits = Vec::new();
 4739            let mut edits = Vec::new();
 4740            for (edit, prevent_auto_indent) in edits_with_flags {
 4741                if prevent_auto_indent {
 4742                    edits.push(edit);
 4743                } else {
 4744                    auto_indent_edits.push(edit);
 4745                }
 4746            }
 4747            if !edits.is_empty() {
 4748                this.edit(edits, cx);
 4749            }
 4750            if !auto_indent_edits.is_empty() {
 4751                this.edit_with_autoindent(auto_indent_edits, cx);
 4752            }
 4753
 4754            let buffer = this.buffer.read(cx).snapshot(cx);
 4755            let new_selections = selection_info
 4756                .into_iter()
 4757                .map(|(extra_newline_inserted, new_selection)| {
 4758                    let mut cursor = new_selection.end.to_point(&buffer);
 4759                    if extra_newline_inserted {
 4760                        cursor.row -= 1;
 4761                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4762                    }
 4763                    new_selection.map(|_| cursor)
 4764                })
 4765                .collect();
 4766
 4767            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4768            this.refresh_edit_prediction(true, false, window, cx);
 4769        });
 4770    }
 4771
 4772    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4773        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4774
 4775        let buffer = self.buffer.read(cx);
 4776        let snapshot = buffer.snapshot(cx);
 4777
 4778        let mut edits = Vec::new();
 4779        let mut rows = Vec::new();
 4780
 4781        for (rows_inserted, selection) in self
 4782            .selections
 4783            .all_adjusted(&self.display_snapshot(cx))
 4784            .into_iter()
 4785            .enumerate()
 4786        {
 4787            let cursor = selection.head();
 4788            let row = cursor.row;
 4789
 4790            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4791
 4792            let newline = "\n".to_string();
 4793            edits.push((start_of_line..start_of_line, newline));
 4794
 4795            rows.push(row + rows_inserted as u32);
 4796        }
 4797
 4798        self.transact(window, cx, |editor, window, cx| {
 4799            editor.edit(edits, cx);
 4800
 4801            editor.change_selections(Default::default(), window, cx, |s| {
 4802                let mut index = 0;
 4803                s.move_cursors_with(|map, _, _| {
 4804                    let row = rows[index];
 4805                    index += 1;
 4806
 4807                    let point = Point::new(row, 0);
 4808                    let boundary = map.next_line_boundary(point).1;
 4809                    let clipped = map.clip_point(boundary, Bias::Left);
 4810
 4811                    (clipped, SelectionGoal::None)
 4812                });
 4813            });
 4814
 4815            let mut indent_edits = Vec::new();
 4816            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4817            for row in rows {
 4818                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4819                for (row, indent) in indents {
 4820                    if indent.len == 0 {
 4821                        continue;
 4822                    }
 4823
 4824                    let text = match indent.kind {
 4825                        IndentKind::Space => " ".repeat(indent.len as usize),
 4826                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4827                    };
 4828                    let point = Point::new(row.0, 0);
 4829                    indent_edits.push((point..point, text));
 4830                }
 4831            }
 4832            editor.edit(indent_edits, cx);
 4833        });
 4834    }
 4835
 4836    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4837        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4838
 4839        let buffer = self.buffer.read(cx);
 4840        let snapshot = buffer.snapshot(cx);
 4841
 4842        let mut edits = Vec::new();
 4843        let mut rows = Vec::new();
 4844        let mut rows_inserted = 0;
 4845
 4846        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4847            let cursor = selection.head();
 4848            let row = cursor.row;
 4849
 4850            let point = Point::new(row + 1, 0);
 4851            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4852
 4853            let newline = "\n".to_string();
 4854            edits.push((start_of_line..start_of_line, newline));
 4855
 4856            rows_inserted += 1;
 4857            rows.push(row + rows_inserted);
 4858        }
 4859
 4860        self.transact(window, cx, |editor, window, cx| {
 4861            editor.edit(edits, cx);
 4862
 4863            editor.change_selections(Default::default(), window, cx, |s| {
 4864                let mut index = 0;
 4865                s.move_cursors_with(|map, _, _| {
 4866                    let row = rows[index];
 4867                    index += 1;
 4868
 4869                    let point = Point::new(row, 0);
 4870                    let boundary = map.next_line_boundary(point).1;
 4871                    let clipped = map.clip_point(boundary, Bias::Left);
 4872
 4873                    (clipped, SelectionGoal::None)
 4874                });
 4875            });
 4876
 4877            let mut indent_edits = Vec::new();
 4878            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4879            for row in rows {
 4880                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4881                for (row, indent) in indents {
 4882                    if indent.len == 0 {
 4883                        continue;
 4884                    }
 4885
 4886                    let text = match indent.kind {
 4887                        IndentKind::Space => " ".repeat(indent.len as usize),
 4888                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4889                    };
 4890                    let point = Point::new(row.0, 0);
 4891                    indent_edits.push((point..point, text));
 4892                }
 4893            }
 4894            editor.edit(indent_edits, cx);
 4895        });
 4896    }
 4897
 4898    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4899        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4900            original_indent_columns: Vec::new(),
 4901        });
 4902        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4903    }
 4904
 4905    fn insert_with_autoindent_mode(
 4906        &mut self,
 4907        text: &str,
 4908        autoindent_mode: Option<AutoindentMode>,
 4909        window: &mut Window,
 4910        cx: &mut Context<Self>,
 4911    ) {
 4912        if self.read_only(cx) {
 4913            return;
 4914        }
 4915
 4916        let text: Arc<str> = text.into();
 4917        self.transact(window, cx, |this, window, cx| {
 4918            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4919            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4920                let anchors = {
 4921                    let snapshot = buffer.read(cx);
 4922                    old_selections
 4923                        .iter()
 4924                        .map(|s| {
 4925                            let anchor = snapshot.anchor_after(s.head());
 4926                            s.map(|_| anchor)
 4927                        })
 4928                        .collect::<Vec<_>>()
 4929                };
 4930                buffer.edit(
 4931                    old_selections
 4932                        .iter()
 4933                        .map(|s| (s.start..s.end, text.clone())),
 4934                    autoindent_mode,
 4935                    cx,
 4936                );
 4937                anchors
 4938            });
 4939
 4940            this.change_selections(Default::default(), window, cx, |s| {
 4941                s.select_anchors(selection_anchors);
 4942            });
 4943
 4944            cx.notify();
 4945        });
 4946    }
 4947
 4948    fn trigger_completion_on_input(
 4949        &mut self,
 4950        text: &str,
 4951        trigger_in_words: bool,
 4952        window: &mut Window,
 4953        cx: &mut Context<Self>,
 4954    ) {
 4955        let completions_source = self
 4956            .context_menu
 4957            .borrow()
 4958            .as_ref()
 4959            .and_then(|menu| match menu {
 4960                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4961                CodeContextMenu::CodeActions(_) => None,
 4962            });
 4963
 4964        match completions_source {
 4965            Some(CompletionsMenuSource::Words { .. }) => {
 4966                self.open_or_update_completions_menu(
 4967                    Some(CompletionsMenuSource::Words {
 4968                        ignore_threshold: false,
 4969                    }),
 4970                    None,
 4971                    window,
 4972                    cx,
 4973                );
 4974            }
 4975            Some(CompletionsMenuSource::Normal)
 4976            | Some(CompletionsMenuSource::SnippetChoices)
 4977            | None
 4978                if self.is_completion_trigger(
 4979                    text,
 4980                    trigger_in_words,
 4981                    completions_source.is_some(),
 4982                    cx,
 4983                ) =>
 4984            {
 4985                self.show_completions(
 4986                    &ShowCompletions {
 4987                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4988                    },
 4989                    window,
 4990                    cx,
 4991                )
 4992            }
 4993            _ => {
 4994                self.hide_context_menu(window, cx);
 4995            }
 4996        }
 4997    }
 4998
 4999    fn is_completion_trigger(
 5000        &self,
 5001        text: &str,
 5002        trigger_in_words: bool,
 5003        menu_is_open: bool,
 5004        cx: &mut Context<Self>,
 5005    ) -> bool {
 5006        let position = self.selections.newest_anchor().head();
 5007        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5008            return false;
 5009        };
 5010
 5011        if let Some(completion_provider) = &self.completion_provider {
 5012            completion_provider.is_completion_trigger(
 5013                &buffer,
 5014                position.text_anchor,
 5015                text,
 5016                trigger_in_words,
 5017                menu_is_open,
 5018                cx,
 5019            )
 5020        } else {
 5021            false
 5022        }
 5023    }
 5024
 5025    /// If any empty selections is touching the start of its innermost containing autoclose
 5026    /// region, expand it to select the brackets.
 5027    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5028        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5029        let buffer = self.buffer.read(cx).read(cx);
 5030        let new_selections = self
 5031            .selections_with_autoclose_regions(selections, &buffer)
 5032            .map(|(mut selection, region)| {
 5033                if !selection.is_empty() {
 5034                    return selection;
 5035                }
 5036
 5037                if let Some(region) = region {
 5038                    let mut range = region.range.to_offset(&buffer);
 5039                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5040                        range.start -= region.pair.start.len();
 5041                        if buffer.contains_str_at(range.start, &region.pair.start)
 5042                            && buffer.contains_str_at(range.end, &region.pair.end)
 5043                        {
 5044                            range.end += region.pair.end.len();
 5045                            selection.start = range.start;
 5046                            selection.end = range.end;
 5047
 5048                            return selection;
 5049                        }
 5050                    }
 5051                }
 5052
 5053                let always_treat_brackets_as_autoclosed = buffer
 5054                    .language_settings_at(selection.start, cx)
 5055                    .always_treat_brackets_as_autoclosed;
 5056
 5057                if !always_treat_brackets_as_autoclosed {
 5058                    return selection;
 5059                }
 5060
 5061                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5062                    for (pair, enabled) in scope.brackets() {
 5063                        if !enabled || !pair.close {
 5064                            continue;
 5065                        }
 5066
 5067                        if buffer.contains_str_at(selection.start, &pair.end) {
 5068                            let pair_start_len = pair.start.len();
 5069                            if buffer.contains_str_at(
 5070                                selection.start.saturating_sub(pair_start_len),
 5071                                &pair.start,
 5072                            ) {
 5073                                selection.start -= pair_start_len;
 5074                                selection.end += pair.end.len();
 5075
 5076                                return selection;
 5077                            }
 5078                        }
 5079                    }
 5080                }
 5081
 5082                selection
 5083            })
 5084            .collect();
 5085
 5086        drop(buffer);
 5087        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5088            selections.select(new_selections)
 5089        });
 5090    }
 5091
 5092    /// Iterate the given selections, and for each one, find the smallest surrounding
 5093    /// autoclose region. This uses the ordering of the selections and the autoclose
 5094    /// regions to avoid repeated comparisons.
 5095    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5096        &'a self,
 5097        selections: impl IntoIterator<Item = Selection<D>>,
 5098        buffer: &'a MultiBufferSnapshot,
 5099    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5100        let mut i = 0;
 5101        let mut regions = self.autoclose_regions.as_slice();
 5102        selections.into_iter().map(move |selection| {
 5103            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5104
 5105            let mut enclosing = None;
 5106            while let Some(pair_state) = regions.get(i) {
 5107                if pair_state.range.end.to_offset(buffer) < range.start {
 5108                    regions = &regions[i + 1..];
 5109                    i = 0;
 5110                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5111                    break;
 5112                } else {
 5113                    if pair_state.selection_id == selection.id {
 5114                        enclosing = Some(pair_state);
 5115                    }
 5116                    i += 1;
 5117                }
 5118            }
 5119
 5120            (selection, enclosing)
 5121        })
 5122    }
 5123
 5124    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5125    fn invalidate_autoclose_regions(
 5126        &mut self,
 5127        mut selections: &[Selection<Anchor>],
 5128        buffer: &MultiBufferSnapshot,
 5129    ) {
 5130        self.autoclose_regions.retain(|state| {
 5131            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5132                return false;
 5133            }
 5134
 5135            let mut i = 0;
 5136            while let Some(selection) = selections.get(i) {
 5137                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5138                    selections = &selections[1..];
 5139                    continue;
 5140                }
 5141                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5142                    break;
 5143                }
 5144                if selection.id == state.selection_id {
 5145                    return true;
 5146                } else {
 5147                    i += 1;
 5148                }
 5149            }
 5150            false
 5151        });
 5152    }
 5153
 5154    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5155        let offset = position.to_offset(buffer);
 5156        let (word_range, kind) =
 5157            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5158        if offset > word_range.start && kind == Some(CharKind::Word) {
 5159            Some(
 5160                buffer
 5161                    .text_for_range(word_range.start..offset)
 5162                    .collect::<String>(),
 5163            )
 5164        } else {
 5165            None
 5166        }
 5167    }
 5168
 5169    pub fn visible_excerpts(
 5170        &self,
 5171        cx: &mut Context<Editor>,
 5172    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5173        let Some(project) = self.project() else {
 5174            return HashMap::default();
 5175        };
 5176        let project = project.read(cx);
 5177        let multi_buffer = self.buffer().read(cx);
 5178        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5179        let multi_buffer_visible_start = self
 5180            .scroll_manager
 5181            .anchor()
 5182            .anchor
 5183            .to_point(&multi_buffer_snapshot);
 5184        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5185            multi_buffer_visible_start
 5186                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5187            Bias::Left,
 5188        );
 5189        multi_buffer_snapshot
 5190            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5191            .into_iter()
 5192            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5193            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5194                let buffer_file = project::File::from_dyn(buffer.file())?;
 5195                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5196                let worktree_entry = buffer_worktree
 5197                    .read(cx)
 5198                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5199                if worktree_entry.is_ignored {
 5200                    None
 5201                } else {
 5202                    Some((
 5203                        excerpt_id,
 5204                        (
 5205                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5206                            buffer.version().clone(),
 5207                            excerpt_visible_range,
 5208                        ),
 5209                    ))
 5210                }
 5211            })
 5212            .collect()
 5213    }
 5214
 5215    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5216        TextLayoutDetails {
 5217            text_system: window.text_system().clone(),
 5218            editor_style: self.style.clone().unwrap(),
 5219            rem_size: window.rem_size(),
 5220            scroll_anchor: self.scroll_manager.anchor(),
 5221            visible_rows: self.visible_line_count(),
 5222            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5223        }
 5224    }
 5225
 5226    fn trigger_on_type_formatting(
 5227        &self,
 5228        input: String,
 5229        window: &mut Window,
 5230        cx: &mut Context<Self>,
 5231    ) -> Option<Task<Result<()>>> {
 5232        if input.len() != 1 {
 5233            return None;
 5234        }
 5235
 5236        let project = self.project()?;
 5237        let position = self.selections.newest_anchor().head();
 5238        let (buffer, buffer_position) = self
 5239            .buffer
 5240            .read(cx)
 5241            .text_anchor_for_position(position, cx)?;
 5242
 5243        let settings = language_settings::language_settings(
 5244            buffer
 5245                .read(cx)
 5246                .language_at(buffer_position)
 5247                .map(|l| l.name()),
 5248            buffer.read(cx).file(),
 5249            cx,
 5250        );
 5251        if !settings.use_on_type_format {
 5252            return None;
 5253        }
 5254
 5255        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5256        // hence we do LSP request & edit on host side only — add formats to host's history.
 5257        let push_to_lsp_host_history = true;
 5258        // If this is not the host, append its history with new edits.
 5259        let push_to_client_history = project.read(cx).is_via_collab();
 5260
 5261        let on_type_formatting = project.update(cx, |project, cx| {
 5262            project.on_type_format(
 5263                buffer.clone(),
 5264                buffer_position,
 5265                input,
 5266                push_to_lsp_host_history,
 5267                cx,
 5268            )
 5269        });
 5270        Some(cx.spawn_in(window, async move |editor, cx| {
 5271            if let Some(transaction) = on_type_formatting.await? {
 5272                if push_to_client_history {
 5273                    buffer
 5274                        .update(cx, |buffer, _| {
 5275                            buffer.push_transaction(transaction, Instant::now());
 5276                            buffer.finalize_last_transaction();
 5277                        })
 5278                        .ok();
 5279                }
 5280                editor.update(cx, |editor, cx| {
 5281                    editor.refresh_document_highlights(cx);
 5282                })?;
 5283            }
 5284            Ok(())
 5285        }))
 5286    }
 5287
 5288    pub fn show_word_completions(
 5289        &mut self,
 5290        _: &ShowWordCompletions,
 5291        window: &mut Window,
 5292        cx: &mut Context<Self>,
 5293    ) {
 5294        self.open_or_update_completions_menu(
 5295            Some(CompletionsMenuSource::Words {
 5296                ignore_threshold: true,
 5297            }),
 5298            None,
 5299            window,
 5300            cx,
 5301        );
 5302    }
 5303
 5304    pub fn show_completions(
 5305        &mut self,
 5306        options: &ShowCompletions,
 5307        window: &mut Window,
 5308        cx: &mut Context<Self>,
 5309    ) {
 5310        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5311    }
 5312
 5313    fn open_or_update_completions_menu(
 5314        &mut self,
 5315        requested_source: Option<CompletionsMenuSource>,
 5316        trigger: Option<&str>,
 5317        window: &mut Window,
 5318        cx: &mut Context<Self>,
 5319    ) {
 5320        if self.pending_rename.is_some() {
 5321            return;
 5322        }
 5323
 5324        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5325
 5326        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5327        // inserted and selected. To handle that case, the start of the selection is used so that
 5328        // the menu starts with all choices.
 5329        let position = self
 5330            .selections
 5331            .newest_anchor()
 5332            .start
 5333            .bias_right(&multibuffer_snapshot);
 5334        if position.diff_base_anchor.is_some() {
 5335            return;
 5336        }
 5337        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5338        let Some(buffer) = buffer_position
 5339            .buffer_id
 5340            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5341        else {
 5342            return;
 5343        };
 5344        let buffer_snapshot = buffer.read(cx).snapshot();
 5345
 5346        let query: Option<Arc<String>> =
 5347            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5348                .map(|query| query.into());
 5349
 5350        drop(multibuffer_snapshot);
 5351
 5352        // Hide the current completions menu when query is empty. Without this, cached
 5353        // completions from before the trigger char may be reused (#32774).
 5354        if query.is_none() {
 5355            let menu_is_open = matches!(
 5356                self.context_menu.borrow().as_ref(),
 5357                Some(CodeContextMenu::Completions(_))
 5358            );
 5359            if menu_is_open {
 5360                self.hide_context_menu(window, cx);
 5361            }
 5362        }
 5363
 5364        let mut ignore_word_threshold = false;
 5365        let provider = match requested_source {
 5366            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5367            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5368                ignore_word_threshold = ignore_threshold;
 5369                None
 5370            }
 5371            Some(CompletionsMenuSource::SnippetChoices) => {
 5372                log::error!("bug: SnippetChoices requested_source is not handled");
 5373                None
 5374            }
 5375        };
 5376
 5377        let sort_completions = provider
 5378            .as_ref()
 5379            .is_some_and(|provider| provider.sort_completions());
 5380
 5381        let filter_completions = provider
 5382            .as_ref()
 5383            .is_none_or(|provider| provider.filter_completions());
 5384
 5385        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5386            if filter_completions {
 5387                menu.filter(query.clone(), provider.clone(), window, cx);
 5388            }
 5389            // When `is_incomplete` is false, no need to re-query completions when the current query
 5390            // is a suffix of the initial query.
 5391            if !menu.is_incomplete {
 5392                // If the new query is a suffix of the old query (typing more characters) and
 5393                // the previous result was complete, the existing completions can be filtered.
 5394                //
 5395                // Note that this is always true for snippet completions.
 5396                let query_matches = match (&menu.initial_query, &query) {
 5397                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5398                    (None, _) => true,
 5399                    _ => false,
 5400                };
 5401                if query_matches {
 5402                    let position_matches = if menu.initial_position == position {
 5403                        true
 5404                    } else {
 5405                        let snapshot = self.buffer.read(cx).read(cx);
 5406                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5407                    };
 5408                    if position_matches {
 5409                        return;
 5410                    }
 5411                }
 5412            }
 5413        };
 5414
 5415        let trigger_kind = match trigger {
 5416            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5417                CompletionTriggerKind::TRIGGER_CHARACTER
 5418            }
 5419            _ => CompletionTriggerKind::INVOKED,
 5420        };
 5421        let completion_context = CompletionContext {
 5422            trigger_character: trigger.and_then(|trigger| {
 5423                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5424                    Some(String::from(trigger))
 5425                } else {
 5426                    None
 5427                }
 5428            }),
 5429            trigger_kind,
 5430        };
 5431
 5432        let Anchor {
 5433            excerpt_id: buffer_excerpt_id,
 5434            text_anchor: buffer_position,
 5435            ..
 5436        } = buffer_position;
 5437
 5438        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5439            buffer_snapshot.surrounding_word(buffer_position, None)
 5440        {
 5441            let word_to_exclude = buffer_snapshot
 5442                .text_for_range(word_range.clone())
 5443                .collect::<String>();
 5444            (
 5445                buffer_snapshot.anchor_before(word_range.start)
 5446                    ..buffer_snapshot.anchor_after(buffer_position),
 5447                Some(word_to_exclude),
 5448            )
 5449        } else {
 5450            (buffer_position..buffer_position, None)
 5451        };
 5452
 5453        let language = buffer_snapshot
 5454            .language_at(buffer_position)
 5455            .map(|language| language.name());
 5456
 5457        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5458            .completions
 5459            .clone();
 5460
 5461        let show_completion_documentation = buffer_snapshot
 5462            .settings_at(buffer_position, cx)
 5463            .show_completion_documentation;
 5464
 5465        // The document can be large, so stay in reasonable bounds when searching for words,
 5466        // otherwise completion pop-up might be slow to appear.
 5467        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5468        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5469        let min_word_search = buffer_snapshot.clip_point(
 5470            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5471            Bias::Left,
 5472        );
 5473        let max_word_search = buffer_snapshot.clip_point(
 5474            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5475            Bias::Right,
 5476        );
 5477        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5478            ..buffer_snapshot.point_to_offset(max_word_search);
 5479
 5480        let skip_digits = query
 5481            .as_ref()
 5482            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5483
 5484        let omit_word_completions = !self.word_completions_enabled
 5485            || (!ignore_word_threshold
 5486                && match &query {
 5487                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5488                    None => completion_settings.words_min_length != 0,
 5489                });
 5490
 5491        let (mut words, provider_responses) = match &provider {
 5492            Some(provider) => {
 5493                let provider_responses = provider.completions(
 5494                    buffer_excerpt_id,
 5495                    &buffer,
 5496                    buffer_position,
 5497                    completion_context,
 5498                    window,
 5499                    cx,
 5500                );
 5501
 5502                let words = match (omit_word_completions, completion_settings.words) {
 5503                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5504                        Task::ready(BTreeMap::default())
 5505                    }
 5506                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5507                        .background_spawn(async move {
 5508                            buffer_snapshot.words_in_range(WordsQuery {
 5509                                fuzzy_contents: None,
 5510                                range: word_search_range,
 5511                                skip_digits,
 5512                            })
 5513                        }),
 5514                };
 5515
 5516                (words, provider_responses)
 5517            }
 5518            None => {
 5519                let words = if omit_word_completions {
 5520                    Task::ready(BTreeMap::default())
 5521                } else {
 5522                    cx.background_spawn(async move {
 5523                        buffer_snapshot.words_in_range(WordsQuery {
 5524                            fuzzy_contents: None,
 5525                            range: word_search_range,
 5526                            skip_digits,
 5527                        })
 5528                    })
 5529                };
 5530                (words, Task::ready(Ok(Vec::new())))
 5531            }
 5532        };
 5533
 5534        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5535
 5536        let id = post_inc(&mut self.next_completion_id);
 5537        let task = cx.spawn_in(window, async move |editor, cx| {
 5538            let Ok(()) = editor.update(cx, |this, _| {
 5539                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5540            }) else {
 5541                return;
 5542            };
 5543
 5544            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5545            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5546            let mut completions = Vec::new();
 5547            let mut is_incomplete = false;
 5548            let mut display_options: Option<CompletionDisplayOptions> = None;
 5549            if let Some(provider_responses) = provider_responses.await.log_err()
 5550                && !provider_responses.is_empty()
 5551            {
 5552                for response in provider_responses {
 5553                    completions.extend(response.completions);
 5554                    is_incomplete = is_incomplete || response.is_incomplete;
 5555                    match display_options.as_mut() {
 5556                        None => {
 5557                            display_options = Some(response.display_options);
 5558                        }
 5559                        Some(options) => options.merge(&response.display_options),
 5560                    }
 5561                }
 5562                if completion_settings.words == WordsCompletionMode::Fallback {
 5563                    words = Task::ready(BTreeMap::default());
 5564                }
 5565            }
 5566            let display_options = display_options.unwrap_or_default();
 5567
 5568            let mut words = words.await;
 5569            if let Some(word_to_exclude) = &word_to_exclude {
 5570                words.remove(word_to_exclude);
 5571            }
 5572            for lsp_completion in &completions {
 5573                words.remove(&lsp_completion.new_text);
 5574            }
 5575            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5576                replace_range: word_replace_range.clone(),
 5577                new_text: word.clone(),
 5578                label: CodeLabel::plain(word, None),
 5579                icon_path: None,
 5580                documentation: None,
 5581                source: CompletionSource::BufferWord {
 5582                    word_range,
 5583                    resolved: false,
 5584                },
 5585                insert_text_mode: Some(InsertTextMode::AS_IS),
 5586                confirm: None,
 5587            }));
 5588
 5589            let menu = if completions.is_empty() {
 5590                None
 5591            } else {
 5592                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5593                    let languages = editor
 5594                        .workspace
 5595                        .as_ref()
 5596                        .and_then(|(workspace, _)| workspace.upgrade())
 5597                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5598                    let menu = CompletionsMenu::new(
 5599                        id,
 5600                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5601                        sort_completions,
 5602                        show_completion_documentation,
 5603                        position,
 5604                        query.clone(),
 5605                        is_incomplete,
 5606                        buffer.clone(),
 5607                        completions.into(),
 5608                        display_options,
 5609                        snippet_sort_order,
 5610                        languages,
 5611                        language,
 5612                        cx,
 5613                    );
 5614
 5615                    let query = if filter_completions { query } else { None };
 5616                    let matches_task = if let Some(query) = query {
 5617                        menu.do_async_filtering(query, cx)
 5618                    } else {
 5619                        Task::ready(menu.unfiltered_matches())
 5620                    };
 5621                    (menu, matches_task)
 5622                }) else {
 5623                    return;
 5624                };
 5625
 5626                let matches = matches_task.await;
 5627
 5628                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5629                    // Newer menu already set, so exit.
 5630                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5631                        editor.context_menu.borrow().as_ref()
 5632                        && prev_menu.id > id
 5633                    {
 5634                        return;
 5635                    };
 5636
 5637                    // Only valid to take prev_menu because it the new menu is immediately set
 5638                    // below, or the menu is hidden.
 5639                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5640                        editor.context_menu.borrow_mut().take()
 5641                    {
 5642                        let position_matches =
 5643                            if prev_menu.initial_position == menu.initial_position {
 5644                                true
 5645                            } else {
 5646                                let snapshot = editor.buffer.read(cx).read(cx);
 5647                                prev_menu.initial_position.to_offset(&snapshot)
 5648                                    == menu.initial_position.to_offset(&snapshot)
 5649                            };
 5650                        if position_matches {
 5651                            // Preserve markdown cache before `set_filter_results` because it will
 5652                            // try to populate the documentation cache.
 5653                            menu.preserve_markdown_cache(prev_menu);
 5654                        }
 5655                    };
 5656
 5657                    menu.set_filter_results(matches, provider, window, cx);
 5658                }) else {
 5659                    return;
 5660                };
 5661
 5662                menu.visible().then_some(menu)
 5663            };
 5664
 5665            editor
 5666                .update_in(cx, |editor, window, cx| {
 5667                    if editor.focus_handle.is_focused(window)
 5668                        && let Some(menu) = menu
 5669                    {
 5670                        *editor.context_menu.borrow_mut() =
 5671                            Some(CodeContextMenu::Completions(menu));
 5672
 5673                        crate::hover_popover::hide_hover(editor, cx);
 5674                        if editor.show_edit_predictions_in_menu() {
 5675                            editor.update_visible_edit_prediction(window, cx);
 5676                        } else {
 5677                            editor.discard_edit_prediction(false, cx);
 5678                        }
 5679
 5680                        cx.notify();
 5681                        return;
 5682                    }
 5683
 5684                    if editor.completion_tasks.len() <= 1 {
 5685                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5686                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5687                        // If it was already hidden and we don't show edit predictions in the menu,
 5688                        // we should also show the edit prediction when available.
 5689                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5690                            editor.update_visible_edit_prediction(window, cx);
 5691                        }
 5692                    }
 5693                })
 5694                .ok();
 5695        });
 5696
 5697        self.completion_tasks.push((id, task));
 5698    }
 5699
 5700    #[cfg(feature = "test-support")]
 5701    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5702        let menu = self.context_menu.borrow();
 5703        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5704            let completions = menu.completions.borrow();
 5705            Some(completions.to_vec())
 5706        } else {
 5707            None
 5708        }
 5709    }
 5710
 5711    pub fn with_completions_menu_matching_id<R>(
 5712        &self,
 5713        id: CompletionId,
 5714        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5715    ) -> R {
 5716        let mut context_menu = self.context_menu.borrow_mut();
 5717        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5718            return f(None);
 5719        };
 5720        if completions_menu.id != id {
 5721            return f(None);
 5722        }
 5723        f(Some(completions_menu))
 5724    }
 5725
 5726    pub fn confirm_completion(
 5727        &mut self,
 5728        action: &ConfirmCompletion,
 5729        window: &mut Window,
 5730        cx: &mut Context<Self>,
 5731    ) -> Option<Task<Result<()>>> {
 5732        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5733        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5734    }
 5735
 5736    pub fn confirm_completion_insert(
 5737        &mut self,
 5738        _: &ConfirmCompletionInsert,
 5739        window: &mut Window,
 5740        cx: &mut Context<Self>,
 5741    ) -> Option<Task<Result<()>>> {
 5742        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5743        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5744    }
 5745
 5746    pub fn confirm_completion_replace(
 5747        &mut self,
 5748        _: &ConfirmCompletionReplace,
 5749        window: &mut Window,
 5750        cx: &mut Context<Self>,
 5751    ) -> Option<Task<Result<()>>> {
 5752        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5753        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5754    }
 5755
 5756    pub fn compose_completion(
 5757        &mut self,
 5758        action: &ComposeCompletion,
 5759        window: &mut Window,
 5760        cx: &mut Context<Self>,
 5761    ) -> Option<Task<Result<()>>> {
 5762        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5763        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5764    }
 5765
 5766    fn do_completion(
 5767        &mut self,
 5768        item_ix: Option<usize>,
 5769        intent: CompletionIntent,
 5770        window: &mut Window,
 5771        cx: &mut Context<Editor>,
 5772    ) -> Option<Task<Result<()>>> {
 5773        use language::ToOffset as _;
 5774
 5775        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5776        else {
 5777            return None;
 5778        };
 5779
 5780        let candidate_id = {
 5781            let entries = completions_menu.entries.borrow();
 5782            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5783            if self.show_edit_predictions_in_menu() {
 5784                self.discard_edit_prediction(true, cx);
 5785            }
 5786            mat.candidate_id
 5787        };
 5788
 5789        let completion = completions_menu
 5790            .completions
 5791            .borrow()
 5792            .get(candidate_id)?
 5793            .clone();
 5794        cx.stop_propagation();
 5795
 5796        let buffer_handle = completions_menu.buffer.clone();
 5797
 5798        let CompletionEdit {
 5799            new_text,
 5800            snippet,
 5801            replace_range,
 5802        } = process_completion_for_edit(
 5803            &completion,
 5804            intent,
 5805            &buffer_handle,
 5806            &completions_menu.initial_position.text_anchor,
 5807            cx,
 5808        );
 5809
 5810        let buffer = buffer_handle.read(cx);
 5811        let snapshot = self.buffer.read(cx).snapshot(cx);
 5812        let newest_anchor = self.selections.newest_anchor();
 5813        let replace_range_multibuffer = {
 5814            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5815            excerpt.map_range_from_buffer(replace_range.clone())
 5816        };
 5817        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5818            return None;
 5819        }
 5820
 5821        let old_text = buffer
 5822            .text_for_range(replace_range.clone())
 5823            .collect::<String>();
 5824        let lookbehind = newest_anchor
 5825            .start
 5826            .text_anchor
 5827            .to_offset(buffer)
 5828            .saturating_sub(replace_range.start);
 5829        let lookahead = replace_range
 5830            .end
 5831            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5832        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5833        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5834
 5835        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5836        let mut ranges = Vec::new();
 5837        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5838
 5839        for selection in &selections {
 5840            let range = if selection.id == newest_anchor.id {
 5841                replace_range_multibuffer.clone()
 5842            } else {
 5843                let mut range = selection.range();
 5844
 5845                // if prefix is present, don't duplicate it
 5846                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5847                    range.start = range.start.saturating_sub(lookbehind);
 5848
 5849                    // if suffix is also present, mimic the newest cursor and replace it
 5850                    if selection.id != newest_anchor.id
 5851                        && snapshot.contains_str_at(range.end, suffix)
 5852                    {
 5853                        range.end += lookahead;
 5854                    }
 5855                }
 5856                range
 5857            };
 5858
 5859            ranges.push(range.clone());
 5860
 5861            if !self.linked_edit_ranges.is_empty() {
 5862                let start_anchor = snapshot.anchor_before(range.start);
 5863                let end_anchor = snapshot.anchor_after(range.end);
 5864                if let Some(ranges) = self
 5865                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5866                {
 5867                    for (buffer, edits) in ranges {
 5868                        linked_edits
 5869                            .entry(buffer.clone())
 5870                            .or_default()
 5871                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5872                    }
 5873                }
 5874            }
 5875        }
 5876
 5877        let common_prefix_len = old_text
 5878            .chars()
 5879            .zip(new_text.chars())
 5880            .take_while(|(a, b)| a == b)
 5881            .map(|(a, _)| a.len_utf8())
 5882            .sum::<usize>();
 5883
 5884        cx.emit(EditorEvent::InputHandled {
 5885            utf16_range_to_replace: None,
 5886            text: new_text[common_prefix_len..].into(),
 5887        });
 5888
 5889        self.transact(window, cx, |editor, window, cx| {
 5890            if let Some(mut snippet) = snippet {
 5891                snippet.text = new_text.to_string();
 5892                editor
 5893                    .insert_snippet(&ranges, snippet, window, cx)
 5894                    .log_err();
 5895            } else {
 5896                editor.buffer.update(cx, |multi_buffer, cx| {
 5897                    let auto_indent = match completion.insert_text_mode {
 5898                        Some(InsertTextMode::AS_IS) => None,
 5899                        _ => editor.autoindent_mode.clone(),
 5900                    };
 5901                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5902                    multi_buffer.edit(edits, auto_indent, cx);
 5903                });
 5904            }
 5905            for (buffer, edits) in linked_edits {
 5906                buffer.update(cx, |buffer, cx| {
 5907                    let snapshot = buffer.snapshot();
 5908                    let edits = edits
 5909                        .into_iter()
 5910                        .map(|(range, text)| {
 5911                            use text::ToPoint as TP;
 5912                            let end_point = TP::to_point(&range.end, &snapshot);
 5913                            let start_point = TP::to_point(&range.start, &snapshot);
 5914                            (start_point..end_point, text)
 5915                        })
 5916                        .sorted_by_key(|(range, _)| range.start);
 5917                    buffer.edit(edits, None, cx);
 5918                })
 5919            }
 5920
 5921            editor.refresh_edit_prediction(true, false, window, cx);
 5922        });
 5923        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 5924
 5925        let show_new_completions_on_confirm = completion
 5926            .confirm
 5927            .as_ref()
 5928            .is_some_and(|confirm| confirm(intent, window, cx));
 5929        if show_new_completions_on_confirm {
 5930            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5931        }
 5932
 5933        let provider = self.completion_provider.as_ref()?;
 5934        drop(completion);
 5935        let apply_edits = provider.apply_additional_edits_for_completion(
 5936            buffer_handle,
 5937            completions_menu.completions.clone(),
 5938            candidate_id,
 5939            true,
 5940            cx,
 5941        );
 5942
 5943        let editor_settings = EditorSettings::get_global(cx);
 5944        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5945            // After the code completion is finished, users often want to know what signatures are needed.
 5946            // so we should automatically call signature_help
 5947            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5948        }
 5949
 5950        Some(cx.foreground_executor().spawn(async move {
 5951            apply_edits.await?;
 5952            Ok(())
 5953        }))
 5954    }
 5955
 5956    pub fn toggle_code_actions(
 5957        &mut self,
 5958        action: &ToggleCodeActions,
 5959        window: &mut Window,
 5960        cx: &mut Context<Self>,
 5961    ) {
 5962        let quick_launch = action.quick_launch;
 5963        let mut context_menu = self.context_menu.borrow_mut();
 5964        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5965            if code_actions.deployed_from == action.deployed_from {
 5966                // Toggle if we're selecting the same one
 5967                *context_menu = None;
 5968                cx.notify();
 5969                return;
 5970            } else {
 5971                // Otherwise, clear it and start a new one
 5972                *context_menu = None;
 5973                cx.notify();
 5974            }
 5975        }
 5976        drop(context_menu);
 5977        let snapshot = self.snapshot(window, cx);
 5978        let deployed_from = action.deployed_from.clone();
 5979        let action = action.clone();
 5980        self.completion_tasks.clear();
 5981        self.discard_edit_prediction(false, cx);
 5982
 5983        let multibuffer_point = match &action.deployed_from {
 5984            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5985                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5986            }
 5987            _ => self
 5988                .selections
 5989                .newest::<Point>(&snapshot.display_snapshot)
 5990                .head(),
 5991        };
 5992        let Some((buffer, buffer_row)) = snapshot
 5993            .buffer_snapshot()
 5994            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5995            .and_then(|(buffer_snapshot, range)| {
 5996                self.buffer()
 5997                    .read(cx)
 5998                    .buffer(buffer_snapshot.remote_id())
 5999                    .map(|buffer| (buffer, range.start.row))
 6000            })
 6001        else {
 6002            return;
 6003        };
 6004        let buffer_id = buffer.read(cx).remote_id();
 6005        let tasks = self
 6006            .tasks
 6007            .get(&(buffer_id, buffer_row))
 6008            .map(|t| Arc::new(t.to_owned()));
 6009
 6010        if !self.focus_handle.is_focused(window) {
 6011            return;
 6012        }
 6013        let project = self.project.clone();
 6014
 6015        let code_actions_task = match deployed_from {
 6016            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6017            _ => self.code_actions(buffer_row, window, cx),
 6018        };
 6019
 6020        let runnable_task = match deployed_from {
 6021            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6022            _ => {
 6023                let mut task_context_task = Task::ready(None);
 6024                if let Some(tasks) = &tasks
 6025                    && let Some(project) = project
 6026                {
 6027                    task_context_task =
 6028                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6029                }
 6030
 6031                cx.spawn_in(window, {
 6032                    let buffer = buffer.clone();
 6033                    async move |editor, cx| {
 6034                        let task_context = task_context_task.await;
 6035
 6036                        let resolved_tasks =
 6037                            tasks
 6038                                .zip(task_context.clone())
 6039                                .map(|(tasks, task_context)| ResolvedTasks {
 6040                                    templates: tasks.resolve(&task_context).collect(),
 6041                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6042                                        multibuffer_point.row,
 6043                                        tasks.column,
 6044                                    )),
 6045                                });
 6046                        let debug_scenarios = editor
 6047                            .update(cx, |editor, cx| {
 6048                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6049                            })?
 6050                            .await;
 6051                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6052                    }
 6053                })
 6054            }
 6055        };
 6056
 6057        cx.spawn_in(window, async move |editor, cx| {
 6058            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6059            let code_actions = code_actions_task.await;
 6060            let spawn_straight_away = quick_launch
 6061                && resolved_tasks
 6062                    .as_ref()
 6063                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6064                && code_actions
 6065                    .as_ref()
 6066                    .is_none_or(|actions| actions.is_empty())
 6067                && debug_scenarios.is_empty();
 6068
 6069            editor.update_in(cx, |editor, window, cx| {
 6070                crate::hover_popover::hide_hover(editor, cx);
 6071                let actions = CodeActionContents::new(
 6072                    resolved_tasks,
 6073                    code_actions,
 6074                    debug_scenarios,
 6075                    task_context.unwrap_or_default(),
 6076                );
 6077
 6078                // Don't show the menu if there are no actions available
 6079                if actions.is_empty() {
 6080                    cx.notify();
 6081                    return Task::ready(Ok(()));
 6082                }
 6083
 6084                *editor.context_menu.borrow_mut() =
 6085                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6086                        buffer,
 6087                        actions,
 6088                        selected_item: Default::default(),
 6089                        scroll_handle: UniformListScrollHandle::default(),
 6090                        deployed_from,
 6091                    }));
 6092                cx.notify();
 6093                if spawn_straight_away
 6094                    && let Some(task) = editor.confirm_code_action(
 6095                        &ConfirmCodeAction { item_ix: Some(0) },
 6096                        window,
 6097                        cx,
 6098                    )
 6099                {
 6100                    return task;
 6101                }
 6102
 6103                Task::ready(Ok(()))
 6104            })
 6105        })
 6106        .detach_and_log_err(cx);
 6107    }
 6108
 6109    fn debug_scenarios(
 6110        &mut self,
 6111        resolved_tasks: &Option<ResolvedTasks>,
 6112        buffer: &Entity<Buffer>,
 6113        cx: &mut App,
 6114    ) -> Task<Vec<task::DebugScenario>> {
 6115        maybe!({
 6116            let project = self.project()?;
 6117            let dap_store = project.read(cx).dap_store();
 6118            let mut scenarios = vec![];
 6119            let resolved_tasks = resolved_tasks.as_ref()?;
 6120            let buffer = buffer.read(cx);
 6121            let language = buffer.language()?;
 6122            let file = buffer.file();
 6123            let debug_adapter = language_settings(language.name().into(), file, cx)
 6124                .debuggers
 6125                .first()
 6126                .map(SharedString::from)
 6127                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6128
 6129            dap_store.update(cx, |dap_store, cx| {
 6130                for (_, task) in &resolved_tasks.templates {
 6131                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6132                        task.original_task().clone(),
 6133                        debug_adapter.clone().into(),
 6134                        task.display_label().to_owned().into(),
 6135                        cx,
 6136                    );
 6137                    scenarios.push(maybe_scenario);
 6138                }
 6139            });
 6140            Some(cx.background_spawn(async move {
 6141                futures::future::join_all(scenarios)
 6142                    .await
 6143                    .into_iter()
 6144                    .flatten()
 6145                    .collect::<Vec<_>>()
 6146            }))
 6147        })
 6148        .unwrap_or_else(|| Task::ready(vec![]))
 6149    }
 6150
 6151    fn code_actions(
 6152        &mut self,
 6153        buffer_row: u32,
 6154        window: &mut Window,
 6155        cx: &mut Context<Self>,
 6156    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6157        let mut task = self.code_actions_task.take();
 6158        cx.spawn_in(window, async move |editor, cx| {
 6159            while let Some(prev_task) = task {
 6160                prev_task.await.log_err();
 6161                task = editor
 6162                    .update(cx, |this, _| this.code_actions_task.take())
 6163                    .ok()?;
 6164            }
 6165
 6166            editor
 6167                .update(cx, |editor, cx| {
 6168                    editor
 6169                        .available_code_actions
 6170                        .clone()
 6171                        .and_then(|(location, code_actions)| {
 6172                            let snapshot = location.buffer.read(cx).snapshot();
 6173                            let point_range = location.range.to_point(&snapshot);
 6174                            let point_range = point_range.start.row..=point_range.end.row;
 6175                            if point_range.contains(&buffer_row) {
 6176                                Some(code_actions)
 6177                            } else {
 6178                                None
 6179                            }
 6180                        })
 6181                })
 6182                .ok()
 6183                .flatten()
 6184        })
 6185    }
 6186
 6187    pub fn confirm_code_action(
 6188        &mut self,
 6189        action: &ConfirmCodeAction,
 6190        window: &mut Window,
 6191        cx: &mut Context<Self>,
 6192    ) -> Option<Task<Result<()>>> {
 6193        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6194
 6195        let actions_menu =
 6196            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6197                menu
 6198            } else {
 6199                return None;
 6200            };
 6201
 6202        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6203        let action = actions_menu.actions.get(action_ix)?;
 6204        let title = action.label();
 6205        let buffer = actions_menu.buffer;
 6206        let workspace = self.workspace()?;
 6207
 6208        match action {
 6209            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6210                workspace.update(cx, |workspace, cx| {
 6211                    workspace.schedule_resolved_task(
 6212                        task_source_kind,
 6213                        resolved_task,
 6214                        false,
 6215                        window,
 6216                        cx,
 6217                    );
 6218
 6219                    Some(Task::ready(Ok(())))
 6220                })
 6221            }
 6222            CodeActionsItem::CodeAction {
 6223                excerpt_id,
 6224                action,
 6225                provider,
 6226            } => {
 6227                let apply_code_action =
 6228                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6229                let workspace = workspace.downgrade();
 6230                Some(cx.spawn_in(window, async move |editor, cx| {
 6231                    let project_transaction = apply_code_action.await?;
 6232                    Self::open_project_transaction(
 6233                        &editor,
 6234                        workspace,
 6235                        project_transaction,
 6236                        title,
 6237                        cx,
 6238                    )
 6239                    .await
 6240                }))
 6241            }
 6242            CodeActionsItem::DebugScenario(scenario) => {
 6243                let context = actions_menu.actions.context;
 6244
 6245                workspace.update(cx, |workspace, cx| {
 6246                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6247                    workspace.start_debug_session(
 6248                        scenario,
 6249                        context,
 6250                        Some(buffer),
 6251                        None,
 6252                        window,
 6253                        cx,
 6254                    );
 6255                });
 6256                Some(Task::ready(Ok(())))
 6257            }
 6258        }
 6259    }
 6260
 6261    pub async fn open_project_transaction(
 6262        editor: &WeakEntity<Editor>,
 6263        workspace: WeakEntity<Workspace>,
 6264        transaction: ProjectTransaction,
 6265        title: String,
 6266        cx: &mut AsyncWindowContext,
 6267    ) -> Result<()> {
 6268        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6269        cx.update(|_, cx| {
 6270            entries.sort_unstable_by_key(|(buffer, _)| {
 6271                buffer.read(cx).file().map(|f| f.path().clone())
 6272            });
 6273        })?;
 6274        if entries.is_empty() {
 6275            return Ok(());
 6276        }
 6277
 6278        // If the project transaction's edits are all contained within this editor, then
 6279        // avoid opening a new editor to display them.
 6280
 6281        if let [(buffer, transaction)] = &*entries {
 6282            let excerpt = editor.update(cx, |editor, cx| {
 6283                editor
 6284                    .buffer()
 6285                    .read(cx)
 6286                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6287            })?;
 6288            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6289                && excerpted_buffer == *buffer
 6290            {
 6291                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6292                    let excerpt_range = excerpt_range.to_offset(buffer);
 6293                    buffer
 6294                        .edited_ranges_for_transaction::<usize>(transaction)
 6295                        .all(|range| {
 6296                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6297                        })
 6298                })?;
 6299
 6300                if all_edits_within_excerpt {
 6301                    return Ok(());
 6302                }
 6303            }
 6304        }
 6305
 6306        let mut ranges_to_highlight = Vec::new();
 6307        let excerpt_buffer = cx.new(|cx| {
 6308            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6309            for (buffer_handle, transaction) in &entries {
 6310                let edited_ranges = buffer_handle
 6311                    .read(cx)
 6312                    .edited_ranges_for_transaction::<Point>(transaction)
 6313                    .collect::<Vec<_>>();
 6314                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6315                    PathKey::for_buffer(buffer_handle, cx),
 6316                    buffer_handle.clone(),
 6317                    edited_ranges,
 6318                    multibuffer_context_lines(cx),
 6319                    cx,
 6320                );
 6321
 6322                ranges_to_highlight.extend(ranges);
 6323            }
 6324            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6325            multibuffer
 6326        })?;
 6327
 6328        workspace.update_in(cx, |workspace, window, cx| {
 6329            let project = workspace.project().clone();
 6330            let editor =
 6331                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6332            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6333            editor.update(cx, |editor, cx| {
 6334                editor.highlight_background::<Self>(
 6335                    &ranges_to_highlight,
 6336                    |theme| theme.colors().editor_highlighted_line_background,
 6337                    cx,
 6338                );
 6339            });
 6340        })?;
 6341
 6342        Ok(())
 6343    }
 6344
 6345    pub fn clear_code_action_providers(&mut self) {
 6346        self.code_action_providers.clear();
 6347        self.available_code_actions.take();
 6348    }
 6349
 6350    pub fn add_code_action_provider(
 6351        &mut self,
 6352        provider: Rc<dyn CodeActionProvider>,
 6353        window: &mut Window,
 6354        cx: &mut Context<Self>,
 6355    ) {
 6356        if self
 6357            .code_action_providers
 6358            .iter()
 6359            .any(|existing_provider| existing_provider.id() == provider.id())
 6360        {
 6361            return;
 6362        }
 6363
 6364        self.code_action_providers.push(provider);
 6365        self.refresh_code_actions(window, cx);
 6366    }
 6367
 6368    pub fn remove_code_action_provider(
 6369        &mut self,
 6370        id: Arc<str>,
 6371        window: &mut Window,
 6372        cx: &mut Context<Self>,
 6373    ) {
 6374        self.code_action_providers
 6375            .retain(|provider| provider.id() != id);
 6376        self.refresh_code_actions(window, cx);
 6377    }
 6378
 6379    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6380        !self.code_action_providers.is_empty()
 6381            && EditorSettings::get_global(cx).toolbar.code_actions
 6382    }
 6383
 6384    pub fn has_available_code_actions(&self) -> bool {
 6385        self.available_code_actions
 6386            .as_ref()
 6387            .is_some_and(|(_, actions)| !actions.is_empty())
 6388    }
 6389
 6390    fn render_inline_code_actions(
 6391        &self,
 6392        icon_size: ui::IconSize,
 6393        display_row: DisplayRow,
 6394        is_active: bool,
 6395        cx: &mut Context<Self>,
 6396    ) -> AnyElement {
 6397        let show_tooltip = !self.context_menu_visible();
 6398        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6399            .icon_size(icon_size)
 6400            .shape(ui::IconButtonShape::Square)
 6401            .icon_color(ui::Color::Hidden)
 6402            .toggle_state(is_active)
 6403            .when(show_tooltip, |this| {
 6404                this.tooltip({
 6405                    let focus_handle = self.focus_handle.clone();
 6406                    move |_window, cx| {
 6407                        Tooltip::for_action_in(
 6408                            "Toggle Code Actions",
 6409                            &ToggleCodeActions {
 6410                                deployed_from: None,
 6411                                quick_launch: false,
 6412                            },
 6413                            &focus_handle,
 6414                            cx,
 6415                        )
 6416                    }
 6417                })
 6418            })
 6419            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6420                window.focus(&editor.focus_handle(cx));
 6421                editor.toggle_code_actions(
 6422                    &crate::actions::ToggleCodeActions {
 6423                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6424                            display_row,
 6425                        )),
 6426                        quick_launch: false,
 6427                    },
 6428                    window,
 6429                    cx,
 6430                );
 6431            }))
 6432            .into_any_element()
 6433    }
 6434
 6435    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6436        &self.context_menu
 6437    }
 6438
 6439    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6440        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6441            cx.background_executor()
 6442                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6443                .await;
 6444
 6445            let (start_buffer, start, _, end, newest_selection) = this
 6446                .update(cx, |this, cx| {
 6447                    let newest_selection = this.selections.newest_anchor().clone();
 6448                    if newest_selection.head().diff_base_anchor.is_some() {
 6449                        return None;
 6450                    }
 6451                    let display_snapshot = this.display_snapshot(cx);
 6452                    let newest_selection_adjusted =
 6453                        this.selections.newest_adjusted(&display_snapshot);
 6454                    let buffer = this.buffer.read(cx);
 6455
 6456                    let (start_buffer, start) =
 6457                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6458                    let (end_buffer, end) =
 6459                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6460
 6461                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6462                })?
 6463                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6464                .context(
 6465                    "Expected selection to lie in a single buffer when refreshing code actions",
 6466                )?;
 6467            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6468                let providers = this.code_action_providers.clone();
 6469                let tasks = this
 6470                    .code_action_providers
 6471                    .iter()
 6472                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6473                    .collect::<Vec<_>>();
 6474                (providers, tasks)
 6475            })?;
 6476
 6477            let mut actions = Vec::new();
 6478            for (provider, provider_actions) in
 6479                providers.into_iter().zip(future::join_all(tasks).await)
 6480            {
 6481                if let Some(provider_actions) = provider_actions.log_err() {
 6482                    actions.extend(provider_actions.into_iter().map(|action| {
 6483                        AvailableCodeAction {
 6484                            excerpt_id: newest_selection.start.excerpt_id,
 6485                            action,
 6486                            provider: provider.clone(),
 6487                        }
 6488                    }));
 6489                }
 6490            }
 6491
 6492            this.update(cx, |this, cx| {
 6493                this.available_code_actions = if actions.is_empty() {
 6494                    None
 6495                } else {
 6496                    Some((
 6497                        Location {
 6498                            buffer: start_buffer,
 6499                            range: start..end,
 6500                        },
 6501                        actions.into(),
 6502                    ))
 6503                };
 6504                cx.notify();
 6505            })
 6506        }));
 6507    }
 6508
 6509    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6510        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6511            self.show_git_blame_inline = false;
 6512
 6513            self.show_git_blame_inline_delay_task =
 6514                Some(cx.spawn_in(window, async move |this, cx| {
 6515                    cx.background_executor().timer(delay).await;
 6516
 6517                    this.update(cx, |this, cx| {
 6518                        this.show_git_blame_inline = true;
 6519                        cx.notify();
 6520                    })
 6521                    .log_err();
 6522                }));
 6523        }
 6524    }
 6525
 6526    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6527        let snapshot = self.snapshot(window, cx);
 6528        let cursor = self
 6529            .selections
 6530            .newest::<Point>(&snapshot.display_snapshot)
 6531            .head();
 6532        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6533        else {
 6534            return;
 6535        };
 6536
 6537        let Some(blame) = self.blame.as_ref() else {
 6538            return;
 6539        };
 6540
 6541        let row_info = RowInfo {
 6542            buffer_id: Some(buffer.remote_id()),
 6543            buffer_row: Some(point.row),
 6544            ..Default::default()
 6545        };
 6546        let Some((buffer, blame_entry)) = blame
 6547            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6548            .flatten()
 6549        else {
 6550            return;
 6551        };
 6552
 6553        let anchor = self.selections.newest_anchor().head();
 6554        let position = self.to_pixel_point(anchor, &snapshot, window);
 6555        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6556            self.show_blame_popover(
 6557                buffer,
 6558                &blame_entry,
 6559                position + last_bounds.origin,
 6560                true,
 6561                cx,
 6562            );
 6563        };
 6564    }
 6565
 6566    fn show_blame_popover(
 6567        &mut self,
 6568        buffer: BufferId,
 6569        blame_entry: &BlameEntry,
 6570        position: gpui::Point<Pixels>,
 6571        ignore_timeout: bool,
 6572        cx: &mut Context<Self>,
 6573    ) {
 6574        if let Some(state) = &mut self.inline_blame_popover {
 6575            state.hide_task.take();
 6576        } else {
 6577            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6578            let blame_entry = blame_entry.clone();
 6579            let show_task = cx.spawn(async move |editor, cx| {
 6580                if !ignore_timeout {
 6581                    cx.background_executor()
 6582                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6583                        .await;
 6584                }
 6585                editor
 6586                    .update(cx, |editor, cx| {
 6587                        editor.inline_blame_popover_show_task.take();
 6588                        let Some(blame) = editor.blame.as_ref() else {
 6589                            return;
 6590                        };
 6591                        let blame = blame.read(cx);
 6592                        let details = blame.details_for_entry(buffer, &blame_entry);
 6593                        let markdown = cx.new(|cx| {
 6594                            Markdown::new(
 6595                                details
 6596                                    .as_ref()
 6597                                    .map(|message| message.message.clone())
 6598                                    .unwrap_or_default(),
 6599                                None,
 6600                                None,
 6601                                cx,
 6602                            )
 6603                        });
 6604                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6605                            position,
 6606                            hide_task: None,
 6607                            popover_bounds: None,
 6608                            popover_state: InlineBlamePopoverState {
 6609                                scroll_handle: ScrollHandle::new(),
 6610                                commit_message: details,
 6611                                markdown,
 6612                            },
 6613                            keyboard_grace: ignore_timeout,
 6614                        });
 6615                        cx.notify();
 6616                    })
 6617                    .ok();
 6618            });
 6619            self.inline_blame_popover_show_task = Some(show_task);
 6620        }
 6621    }
 6622
 6623    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6624        self.inline_blame_popover_show_task.take();
 6625        if let Some(state) = &mut self.inline_blame_popover {
 6626            let hide_task = cx.spawn(async move |editor, cx| {
 6627                if !ignore_timeout {
 6628                    cx.background_executor()
 6629                        .timer(std::time::Duration::from_millis(100))
 6630                        .await;
 6631                }
 6632                editor
 6633                    .update(cx, |editor, cx| {
 6634                        editor.inline_blame_popover.take();
 6635                        cx.notify();
 6636                    })
 6637                    .ok();
 6638            });
 6639            state.hide_task = Some(hide_task);
 6640            true
 6641        } else {
 6642            false
 6643        }
 6644    }
 6645
 6646    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6647        if self.pending_rename.is_some() {
 6648            return None;
 6649        }
 6650
 6651        let provider = self.semantics_provider.clone()?;
 6652        let buffer = self.buffer.read(cx);
 6653        let newest_selection = self.selections.newest_anchor().clone();
 6654        let cursor_position = newest_selection.head();
 6655        let (cursor_buffer, cursor_buffer_position) =
 6656            buffer.text_anchor_for_position(cursor_position, cx)?;
 6657        let (tail_buffer, tail_buffer_position) =
 6658            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6659        if cursor_buffer != tail_buffer {
 6660            return None;
 6661        }
 6662
 6663        let snapshot = cursor_buffer.read(cx).snapshot();
 6664        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6665        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6666        if start_word_range != end_word_range {
 6667            self.document_highlights_task.take();
 6668            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6669            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6670            return None;
 6671        }
 6672
 6673        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6674        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6675            cx.background_executor()
 6676                .timer(Duration::from_millis(debounce))
 6677                .await;
 6678
 6679            let highlights = if let Some(highlights) = cx
 6680                .update(|cx| {
 6681                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6682                })
 6683                .ok()
 6684                .flatten()
 6685            {
 6686                highlights.await.log_err()
 6687            } else {
 6688                None
 6689            };
 6690
 6691            if let Some(highlights) = highlights {
 6692                this.update(cx, |this, cx| {
 6693                    if this.pending_rename.is_some() {
 6694                        return;
 6695                    }
 6696
 6697                    let buffer = this.buffer.read(cx);
 6698                    if buffer
 6699                        .text_anchor_for_position(cursor_position, cx)
 6700                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6701                    {
 6702                        return;
 6703                    }
 6704
 6705                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6706                    let mut write_ranges = Vec::new();
 6707                    let mut read_ranges = Vec::new();
 6708                    for highlight in highlights {
 6709                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6710                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6711                        {
 6712                            let start = highlight
 6713                                .range
 6714                                .start
 6715                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6716                            let end = highlight
 6717                                .range
 6718                                .end
 6719                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6720                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6721                                continue;
 6722                            }
 6723
 6724                            let range =
 6725                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6726                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6727                                write_ranges.push(range);
 6728                            } else {
 6729                                read_ranges.push(range);
 6730                            }
 6731                        }
 6732                    }
 6733
 6734                    this.highlight_background::<DocumentHighlightRead>(
 6735                        &read_ranges,
 6736                        |theme| theme.colors().editor_document_highlight_read_background,
 6737                        cx,
 6738                    );
 6739                    this.highlight_background::<DocumentHighlightWrite>(
 6740                        &write_ranges,
 6741                        |theme| theme.colors().editor_document_highlight_write_background,
 6742                        cx,
 6743                    );
 6744                    cx.notify();
 6745                })
 6746                .log_err();
 6747            }
 6748        }));
 6749        None
 6750    }
 6751
 6752    fn prepare_highlight_query_from_selection(
 6753        &mut self,
 6754        window: &Window,
 6755        cx: &mut Context<Editor>,
 6756    ) -> Option<(String, Range<Anchor>)> {
 6757        if matches!(self.mode, EditorMode::SingleLine) {
 6758            return None;
 6759        }
 6760        if !EditorSettings::get_global(cx).selection_highlight {
 6761            return None;
 6762        }
 6763        if self.selections.count() != 1 || self.selections.line_mode() {
 6764            return None;
 6765        }
 6766        let snapshot = self.snapshot(window, cx);
 6767        let selection = self.selections.newest::<Point>(&snapshot);
 6768        // If the selection spans multiple rows OR it is empty
 6769        if selection.start.row != selection.end.row
 6770            || selection.start.column == selection.end.column
 6771        {
 6772            return None;
 6773        }
 6774        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6775        let query = snapshot
 6776            .buffer_snapshot()
 6777            .text_for_range(selection_anchor_range.clone())
 6778            .collect::<String>();
 6779        if query.trim().is_empty() {
 6780            return None;
 6781        }
 6782        Some((query, selection_anchor_range))
 6783    }
 6784
 6785    fn update_selection_occurrence_highlights(
 6786        &mut self,
 6787        query_text: String,
 6788        query_range: Range<Anchor>,
 6789        multi_buffer_range_to_query: Range<Point>,
 6790        use_debounce: bool,
 6791        window: &mut Window,
 6792        cx: &mut Context<Editor>,
 6793    ) -> Task<()> {
 6794        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6795        cx.spawn_in(window, async move |editor, cx| {
 6796            if use_debounce {
 6797                cx.background_executor()
 6798                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6799                    .await;
 6800            }
 6801            let match_task = cx.background_spawn(async move {
 6802                let buffer_ranges = multi_buffer_snapshot
 6803                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6804                    .into_iter()
 6805                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6806                let mut match_ranges = Vec::new();
 6807                let Ok(regex) = project::search::SearchQuery::text(
 6808                    query_text.clone(),
 6809                    false,
 6810                    false,
 6811                    false,
 6812                    Default::default(),
 6813                    Default::default(),
 6814                    false,
 6815                    None,
 6816                ) else {
 6817                    return Vec::default();
 6818                };
 6819                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6820                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6821                    match_ranges.extend(
 6822                        regex
 6823                            .search(buffer_snapshot, Some(search_range.clone()))
 6824                            .await
 6825                            .into_iter()
 6826                            .filter_map(|match_range| {
 6827                                let match_start = buffer_snapshot
 6828                                    .anchor_after(search_range.start + match_range.start);
 6829                                let match_end = buffer_snapshot
 6830                                    .anchor_before(search_range.start + match_range.end);
 6831                                let match_anchor_range = Anchor::range_in_buffer(
 6832                                    excerpt_id,
 6833                                    buffer_snapshot.remote_id(),
 6834                                    match_start..match_end,
 6835                                );
 6836                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6837                            }),
 6838                    );
 6839                }
 6840                match_ranges
 6841            });
 6842            let match_ranges = match_task.await;
 6843            editor
 6844                .update_in(cx, |editor, _, cx| {
 6845                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6846                    if !match_ranges.is_empty() {
 6847                        editor.highlight_background::<SelectedTextHighlight>(
 6848                            &match_ranges,
 6849                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6850                            cx,
 6851                        )
 6852                    }
 6853                })
 6854                .log_err();
 6855        })
 6856    }
 6857
 6858    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6859        struct NewlineFold;
 6860        let type_id = std::any::TypeId::of::<NewlineFold>();
 6861        if !self.mode.is_single_line() {
 6862            return;
 6863        }
 6864        let snapshot = self.snapshot(window, cx);
 6865        if snapshot.buffer_snapshot().max_point().row == 0 {
 6866            return;
 6867        }
 6868        let task = cx.background_spawn(async move {
 6869            let new_newlines = snapshot
 6870                .buffer_chars_at(0)
 6871                .filter_map(|(c, i)| {
 6872                    if c == '\n' {
 6873                        Some(
 6874                            snapshot.buffer_snapshot().anchor_after(i)
 6875                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6876                        )
 6877                    } else {
 6878                        None
 6879                    }
 6880                })
 6881                .collect::<Vec<_>>();
 6882            let existing_newlines = snapshot
 6883                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6884                .filter_map(|fold| {
 6885                    if fold.placeholder.type_tag == Some(type_id) {
 6886                        Some(fold.range.start..fold.range.end)
 6887                    } else {
 6888                        None
 6889                    }
 6890                })
 6891                .collect::<Vec<_>>();
 6892
 6893            (new_newlines, existing_newlines)
 6894        });
 6895        self.folding_newlines = cx.spawn(async move |this, cx| {
 6896            let (new_newlines, existing_newlines) = task.await;
 6897            if new_newlines == existing_newlines {
 6898                return;
 6899            }
 6900            let placeholder = FoldPlaceholder {
 6901                render: Arc::new(move |_, _, cx| {
 6902                    div()
 6903                        .bg(cx.theme().status().hint_background)
 6904                        .border_b_1()
 6905                        .size_full()
 6906                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6907                        .border_color(cx.theme().status().hint)
 6908                        .child("\\n")
 6909                        .into_any()
 6910                }),
 6911                constrain_width: false,
 6912                merge_adjacent: false,
 6913                type_tag: Some(type_id),
 6914            };
 6915            let creases = new_newlines
 6916                .into_iter()
 6917                .map(|range| Crease::simple(range, placeholder.clone()))
 6918                .collect();
 6919            this.update(cx, |this, cx| {
 6920                this.display_map.update(cx, |display_map, cx| {
 6921                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6922                    display_map.fold(creases, cx);
 6923                });
 6924            })
 6925            .ok();
 6926        });
 6927    }
 6928
 6929    fn refresh_selected_text_highlights(
 6930        &mut self,
 6931        on_buffer_edit: bool,
 6932        window: &mut Window,
 6933        cx: &mut Context<Editor>,
 6934    ) {
 6935        let Some((query_text, query_range)) =
 6936            self.prepare_highlight_query_from_selection(window, cx)
 6937        else {
 6938            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6939            self.quick_selection_highlight_task.take();
 6940            self.debounced_selection_highlight_task.take();
 6941            return;
 6942        };
 6943        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6944        if on_buffer_edit
 6945            || self
 6946                .quick_selection_highlight_task
 6947                .as_ref()
 6948                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6949        {
 6950            let multi_buffer_visible_start = self
 6951                .scroll_manager
 6952                .anchor()
 6953                .anchor
 6954                .to_point(&multi_buffer_snapshot);
 6955            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6956                multi_buffer_visible_start
 6957                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6958                Bias::Left,
 6959            );
 6960            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6961            self.quick_selection_highlight_task = Some((
 6962                query_range.clone(),
 6963                self.update_selection_occurrence_highlights(
 6964                    query_text.clone(),
 6965                    query_range.clone(),
 6966                    multi_buffer_visible_range,
 6967                    false,
 6968                    window,
 6969                    cx,
 6970                ),
 6971            ));
 6972        }
 6973        if on_buffer_edit
 6974            || self
 6975                .debounced_selection_highlight_task
 6976                .as_ref()
 6977                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6978        {
 6979            let multi_buffer_start = multi_buffer_snapshot
 6980                .anchor_before(0)
 6981                .to_point(&multi_buffer_snapshot);
 6982            let multi_buffer_end = multi_buffer_snapshot
 6983                .anchor_after(multi_buffer_snapshot.len())
 6984                .to_point(&multi_buffer_snapshot);
 6985            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6986            self.debounced_selection_highlight_task = Some((
 6987                query_range.clone(),
 6988                self.update_selection_occurrence_highlights(
 6989                    query_text,
 6990                    query_range,
 6991                    multi_buffer_full_range,
 6992                    true,
 6993                    window,
 6994                    cx,
 6995                ),
 6996            ));
 6997        }
 6998    }
 6999
 7000    pub fn refresh_edit_prediction(
 7001        &mut self,
 7002        debounce: bool,
 7003        user_requested: bool,
 7004        window: &mut Window,
 7005        cx: &mut Context<Self>,
 7006    ) -> Option<()> {
 7007        if DisableAiSettings::get_global(cx).disable_ai {
 7008            return None;
 7009        }
 7010
 7011        let provider = self.edit_prediction_provider()?;
 7012        let cursor = self.selections.newest_anchor().head();
 7013        let (buffer, cursor_buffer_position) =
 7014            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7015
 7016        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7017            self.discard_edit_prediction(false, cx);
 7018            return None;
 7019        }
 7020
 7021        self.update_visible_edit_prediction(window, cx);
 7022
 7023        if !user_requested
 7024            && (!self.should_show_edit_predictions()
 7025                || !self.is_focused(window)
 7026                || buffer.read(cx).is_empty())
 7027        {
 7028            self.discard_edit_prediction(false, cx);
 7029            return None;
 7030        }
 7031
 7032        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7033        Some(())
 7034    }
 7035
 7036    fn show_edit_predictions_in_menu(&self) -> bool {
 7037        match self.edit_prediction_settings {
 7038            EditPredictionSettings::Disabled => false,
 7039            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7040        }
 7041    }
 7042
 7043    pub fn edit_predictions_enabled(&self) -> bool {
 7044        match self.edit_prediction_settings {
 7045            EditPredictionSettings::Disabled => false,
 7046            EditPredictionSettings::Enabled { .. } => true,
 7047        }
 7048    }
 7049
 7050    fn edit_prediction_requires_modifier(&self) -> bool {
 7051        match self.edit_prediction_settings {
 7052            EditPredictionSettings::Disabled => false,
 7053            EditPredictionSettings::Enabled {
 7054                preview_requires_modifier,
 7055                ..
 7056            } => preview_requires_modifier,
 7057        }
 7058    }
 7059
 7060    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7061        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7062            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7063            self.discard_edit_prediction(false, cx);
 7064        } else {
 7065            let selection = self.selections.newest_anchor();
 7066            let cursor = selection.head();
 7067
 7068            if let Some((buffer, cursor_buffer_position)) =
 7069                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7070            {
 7071                self.edit_prediction_settings =
 7072                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7073            }
 7074        }
 7075    }
 7076
 7077    fn edit_prediction_settings_at_position(
 7078        &self,
 7079        buffer: &Entity<Buffer>,
 7080        buffer_position: language::Anchor,
 7081        cx: &App,
 7082    ) -> EditPredictionSettings {
 7083        if !self.mode.is_full()
 7084            || !self.show_edit_predictions_override.unwrap_or(true)
 7085            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7086        {
 7087            return EditPredictionSettings::Disabled;
 7088        }
 7089
 7090        let buffer = buffer.read(cx);
 7091
 7092        let file = buffer.file();
 7093
 7094        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7095            return EditPredictionSettings::Disabled;
 7096        };
 7097
 7098        let by_provider = matches!(
 7099            self.menu_edit_predictions_policy,
 7100            MenuEditPredictionsPolicy::ByProvider
 7101        );
 7102
 7103        let show_in_menu = by_provider
 7104            && self
 7105                .edit_prediction_provider
 7106                .as_ref()
 7107                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7108
 7109        let preview_requires_modifier =
 7110            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7111
 7112        EditPredictionSettings::Enabled {
 7113            show_in_menu,
 7114            preview_requires_modifier,
 7115        }
 7116    }
 7117
 7118    fn should_show_edit_predictions(&self) -> bool {
 7119        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7120    }
 7121
 7122    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7123        matches!(
 7124            self.edit_prediction_preview,
 7125            EditPredictionPreview::Active { .. }
 7126        )
 7127    }
 7128
 7129    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7130        let cursor = self.selections.newest_anchor().head();
 7131        if let Some((buffer, cursor_position)) =
 7132            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7133        {
 7134            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7135        } else {
 7136            false
 7137        }
 7138    }
 7139
 7140    pub fn supports_minimap(&self, cx: &App) -> bool {
 7141        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7142    }
 7143
 7144    fn edit_predictions_enabled_in_buffer(
 7145        &self,
 7146        buffer: &Entity<Buffer>,
 7147        buffer_position: language::Anchor,
 7148        cx: &App,
 7149    ) -> bool {
 7150        maybe!({
 7151            if self.read_only(cx) {
 7152                return Some(false);
 7153            }
 7154            let provider = self.edit_prediction_provider()?;
 7155            if !provider.is_enabled(buffer, buffer_position, cx) {
 7156                return Some(false);
 7157            }
 7158            let buffer = buffer.read(cx);
 7159            let Some(file) = buffer.file() else {
 7160                return Some(true);
 7161            };
 7162            let settings = all_language_settings(Some(file), cx);
 7163            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7164        })
 7165        .unwrap_or(false)
 7166    }
 7167
 7168    fn cycle_edit_prediction(
 7169        &mut self,
 7170        direction: Direction,
 7171        window: &mut Window,
 7172        cx: &mut Context<Self>,
 7173    ) -> Option<()> {
 7174        let provider = self.edit_prediction_provider()?;
 7175        let cursor = self.selections.newest_anchor().head();
 7176        let (buffer, cursor_buffer_position) =
 7177            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7178        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7179            return None;
 7180        }
 7181
 7182        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7183        self.update_visible_edit_prediction(window, cx);
 7184
 7185        Some(())
 7186    }
 7187
 7188    pub fn show_edit_prediction(
 7189        &mut self,
 7190        _: &ShowEditPrediction,
 7191        window: &mut Window,
 7192        cx: &mut Context<Self>,
 7193    ) {
 7194        if !self.has_active_edit_prediction() {
 7195            self.refresh_edit_prediction(false, true, window, cx);
 7196            return;
 7197        }
 7198
 7199        self.update_visible_edit_prediction(window, cx);
 7200    }
 7201
 7202    pub fn display_cursor_names(
 7203        &mut self,
 7204        _: &DisplayCursorNames,
 7205        window: &mut Window,
 7206        cx: &mut Context<Self>,
 7207    ) {
 7208        self.show_cursor_names(window, cx);
 7209    }
 7210
 7211    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7212        self.show_cursor_names = true;
 7213        cx.notify();
 7214        cx.spawn_in(window, async move |this, cx| {
 7215            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7216            this.update(cx, |this, cx| {
 7217                this.show_cursor_names = false;
 7218                cx.notify()
 7219            })
 7220            .ok()
 7221        })
 7222        .detach();
 7223    }
 7224
 7225    pub fn next_edit_prediction(
 7226        &mut self,
 7227        _: &NextEditPrediction,
 7228        window: &mut Window,
 7229        cx: &mut Context<Self>,
 7230    ) {
 7231        if self.has_active_edit_prediction() {
 7232            self.cycle_edit_prediction(Direction::Next, window, cx);
 7233        } else {
 7234            let is_copilot_disabled = self
 7235                .refresh_edit_prediction(false, true, window, cx)
 7236                .is_none();
 7237            if is_copilot_disabled {
 7238                cx.propagate();
 7239            }
 7240        }
 7241    }
 7242
 7243    pub fn previous_edit_prediction(
 7244        &mut self,
 7245        _: &PreviousEditPrediction,
 7246        window: &mut Window,
 7247        cx: &mut Context<Self>,
 7248    ) {
 7249        if self.has_active_edit_prediction() {
 7250            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7251        } else {
 7252            let is_copilot_disabled = self
 7253                .refresh_edit_prediction(false, true, window, cx)
 7254                .is_none();
 7255            if is_copilot_disabled {
 7256                cx.propagate();
 7257            }
 7258        }
 7259    }
 7260
 7261    pub fn accept_edit_prediction(
 7262        &mut self,
 7263        _: &AcceptEditPrediction,
 7264        window: &mut Window,
 7265        cx: &mut Context<Self>,
 7266    ) {
 7267        if self.show_edit_predictions_in_menu() {
 7268            self.hide_context_menu(window, cx);
 7269        }
 7270
 7271        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7272            return;
 7273        };
 7274
 7275        match &active_edit_prediction.completion {
 7276            EditPrediction::MoveWithin { target, .. } => {
 7277                let target = *target;
 7278
 7279                if let Some(position_map) = &self.last_position_map {
 7280                    if position_map
 7281                        .visible_row_range
 7282                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7283                        || !self.edit_prediction_requires_modifier()
 7284                    {
 7285                        self.unfold_ranges(&[target..target], true, false, cx);
 7286                        // Note that this is also done in vim's handler of the Tab action.
 7287                        self.change_selections(
 7288                            SelectionEffects::scroll(Autoscroll::newest()),
 7289                            window,
 7290                            cx,
 7291                            |selections| {
 7292                                selections.select_anchor_ranges([target..target]);
 7293                            },
 7294                        );
 7295                        self.clear_row_highlights::<EditPredictionPreview>();
 7296
 7297                        self.edit_prediction_preview
 7298                            .set_previous_scroll_position(None);
 7299                    } else {
 7300                        self.edit_prediction_preview
 7301                            .set_previous_scroll_position(Some(
 7302                                position_map.snapshot.scroll_anchor,
 7303                            ));
 7304
 7305                        self.highlight_rows::<EditPredictionPreview>(
 7306                            target..target,
 7307                            cx.theme().colors().editor_highlighted_line_background,
 7308                            RowHighlightOptions {
 7309                                autoscroll: true,
 7310                                ..Default::default()
 7311                            },
 7312                            cx,
 7313                        );
 7314                        self.request_autoscroll(Autoscroll::fit(), cx);
 7315                    }
 7316                }
 7317            }
 7318            EditPrediction::MoveOutside { snapshot, target } => {
 7319                if let Some(workspace) = self.workspace() {
 7320                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7321                        .detach_and_log_err(cx);
 7322                }
 7323            }
 7324            EditPrediction::Edit { edits, .. } => {
 7325                self.report_edit_prediction_event(
 7326                    active_edit_prediction.completion_id.clone(),
 7327                    true,
 7328                    cx,
 7329                );
 7330
 7331                if let Some(provider) = self.edit_prediction_provider() {
 7332                    provider.accept(cx);
 7333                }
 7334
 7335                // Store the transaction ID and selections before applying the edit
 7336                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7337
 7338                let snapshot = self.buffer.read(cx).snapshot(cx);
 7339                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7340
 7341                self.buffer.update(cx, |buffer, cx| {
 7342                    buffer.edit(edits.iter().cloned(), None, cx)
 7343                });
 7344
 7345                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7346                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7347                });
 7348
 7349                let selections = self.selections.disjoint_anchors_arc();
 7350                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7351                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7352                    if has_new_transaction {
 7353                        self.selection_history
 7354                            .insert_transaction(transaction_id_now, selections);
 7355                    }
 7356                }
 7357
 7358                self.update_visible_edit_prediction(window, cx);
 7359                if self.active_edit_prediction.is_none() {
 7360                    self.refresh_edit_prediction(true, true, window, cx);
 7361                }
 7362
 7363                cx.notify();
 7364            }
 7365        }
 7366
 7367        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7368    }
 7369
 7370    pub fn accept_partial_edit_prediction(
 7371        &mut self,
 7372        _: &AcceptPartialEditPrediction,
 7373        window: &mut Window,
 7374        cx: &mut Context<Self>,
 7375    ) {
 7376        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7377            return;
 7378        };
 7379        if self.selections.count() != 1 {
 7380            return;
 7381        }
 7382
 7383        match &active_edit_prediction.completion {
 7384            EditPrediction::MoveWithin { target, .. } => {
 7385                let target = *target;
 7386                self.change_selections(
 7387                    SelectionEffects::scroll(Autoscroll::newest()),
 7388                    window,
 7389                    cx,
 7390                    |selections| {
 7391                        selections.select_anchor_ranges([target..target]);
 7392                    },
 7393                );
 7394            }
 7395            EditPrediction::MoveOutside { snapshot, target } => {
 7396                if let Some(workspace) = self.workspace() {
 7397                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7398                        .detach_and_log_err(cx);
 7399                }
 7400            }
 7401            EditPrediction::Edit { edits, .. } => {
 7402                self.report_edit_prediction_event(
 7403                    active_edit_prediction.completion_id.clone(),
 7404                    true,
 7405                    cx,
 7406                );
 7407
 7408                // Find an insertion that starts at the cursor position.
 7409                let snapshot = self.buffer.read(cx).snapshot(cx);
 7410                let cursor_offset = self
 7411                    .selections
 7412                    .newest::<usize>(&self.display_snapshot(cx))
 7413                    .head();
 7414                let insertion = edits.iter().find_map(|(range, text)| {
 7415                    let range = range.to_offset(&snapshot);
 7416                    if range.is_empty() && range.start == cursor_offset {
 7417                        Some(text)
 7418                    } else {
 7419                        None
 7420                    }
 7421                });
 7422
 7423                if let Some(text) = insertion {
 7424                    let mut partial_completion = text
 7425                        .chars()
 7426                        .by_ref()
 7427                        .take_while(|c| c.is_alphabetic())
 7428                        .collect::<String>();
 7429                    if partial_completion.is_empty() {
 7430                        partial_completion = text
 7431                            .chars()
 7432                            .by_ref()
 7433                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7434                            .collect::<String>();
 7435                    }
 7436
 7437                    cx.emit(EditorEvent::InputHandled {
 7438                        utf16_range_to_replace: None,
 7439                        text: partial_completion.clone().into(),
 7440                    });
 7441
 7442                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7443
 7444                    self.refresh_edit_prediction(true, true, window, cx);
 7445                    cx.notify();
 7446                } else {
 7447                    self.accept_edit_prediction(&Default::default(), window, cx);
 7448                }
 7449            }
 7450        }
 7451    }
 7452
 7453    fn discard_edit_prediction(
 7454        &mut self,
 7455        should_report_edit_prediction_event: bool,
 7456        cx: &mut Context<Self>,
 7457    ) -> bool {
 7458        if should_report_edit_prediction_event {
 7459            let completion_id = self
 7460                .active_edit_prediction
 7461                .as_ref()
 7462                .and_then(|active_completion| active_completion.completion_id.clone());
 7463
 7464            self.report_edit_prediction_event(completion_id, false, cx);
 7465        }
 7466
 7467        if let Some(provider) = self.edit_prediction_provider() {
 7468            provider.discard(cx);
 7469        }
 7470
 7471        self.take_active_edit_prediction(cx)
 7472    }
 7473
 7474    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7475        let Some(provider) = self.edit_prediction_provider() else {
 7476            return;
 7477        };
 7478
 7479        let Some((_, buffer, _)) = self
 7480            .buffer
 7481            .read(cx)
 7482            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7483        else {
 7484            return;
 7485        };
 7486
 7487        let extension = buffer
 7488            .read(cx)
 7489            .file()
 7490            .and_then(|file| Some(file.path().extension()?.to_string()));
 7491
 7492        let event_type = match accepted {
 7493            true => "Edit Prediction Accepted",
 7494            false => "Edit Prediction Discarded",
 7495        };
 7496        telemetry::event!(
 7497            event_type,
 7498            provider = provider.name(),
 7499            prediction_id = id,
 7500            suggestion_accepted = accepted,
 7501            file_extension = extension,
 7502        );
 7503    }
 7504
 7505    fn open_editor_at_anchor(
 7506        snapshot: &language::BufferSnapshot,
 7507        target: language::Anchor,
 7508        workspace: &Entity<Workspace>,
 7509        window: &mut Window,
 7510        cx: &mut App,
 7511    ) -> Task<Result<()>> {
 7512        workspace.update(cx, |workspace, cx| {
 7513            let path = snapshot.file().map(|file| file.full_path(cx));
 7514            let Some(path) =
 7515                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7516            else {
 7517                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7518            };
 7519            let target = text::ToPoint::to_point(&target, snapshot);
 7520            let item = workspace.open_path(path, None, true, window, cx);
 7521            window.spawn(cx, async move |cx| {
 7522                let Some(editor) = item.await?.downcast::<Editor>() else {
 7523                    return Ok(());
 7524                };
 7525                editor
 7526                    .update_in(cx, |editor, window, cx| {
 7527                        editor.go_to_singleton_buffer_point(target, window, cx);
 7528                    })
 7529                    .ok();
 7530                anyhow::Ok(())
 7531            })
 7532        })
 7533    }
 7534
 7535    pub fn has_active_edit_prediction(&self) -> bool {
 7536        self.active_edit_prediction.is_some()
 7537    }
 7538
 7539    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7540        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7541            return false;
 7542        };
 7543
 7544        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7545        self.clear_highlights::<EditPredictionHighlight>(cx);
 7546        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7547        true
 7548    }
 7549
 7550    /// Returns true when we're displaying the edit prediction popover below the cursor
 7551    /// like we are not previewing and the LSP autocomplete menu is visible
 7552    /// or we are in `when_holding_modifier` mode.
 7553    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7554        if self.edit_prediction_preview_is_active()
 7555            || !self.show_edit_predictions_in_menu()
 7556            || !self.edit_predictions_enabled()
 7557        {
 7558            return false;
 7559        }
 7560
 7561        if self.has_visible_completions_menu() {
 7562            return true;
 7563        }
 7564
 7565        has_completion && self.edit_prediction_requires_modifier()
 7566    }
 7567
 7568    fn handle_modifiers_changed(
 7569        &mut self,
 7570        modifiers: Modifiers,
 7571        position_map: &PositionMap,
 7572        window: &mut Window,
 7573        cx: &mut Context<Self>,
 7574    ) {
 7575        // Ensure that the edit prediction preview is updated, even when not
 7576        // enabled, if there's an active edit prediction preview.
 7577        if self.show_edit_predictions_in_menu()
 7578            || matches!(
 7579                self.edit_prediction_preview,
 7580                EditPredictionPreview::Active { .. }
 7581            )
 7582        {
 7583            self.update_edit_prediction_preview(&modifiers, window, cx);
 7584        }
 7585
 7586        self.update_selection_mode(&modifiers, position_map, window, cx);
 7587
 7588        let mouse_position = window.mouse_position();
 7589        if !position_map.text_hitbox.is_hovered(window) {
 7590            return;
 7591        }
 7592
 7593        self.update_hovered_link(
 7594            position_map.point_for_position(mouse_position),
 7595            &position_map.snapshot,
 7596            modifiers,
 7597            window,
 7598            cx,
 7599        )
 7600    }
 7601
 7602    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7603        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7604            MultiCursorModifier::Alt => modifiers.secondary(),
 7605            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7606        }
 7607    }
 7608
 7609    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7610        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7611            MultiCursorModifier::Alt => modifiers.alt,
 7612            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7613        }
 7614    }
 7615
 7616    fn columnar_selection_mode(
 7617        modifiers: &Modifiers,
 7618        cx: &mut Context<Self>,
 7619    ) -> Option<ColumnarMode> {
 7620        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7621            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7622                Some(ColumnarMode::FromMouse)
 7623            } else if Self::is_alt_pressed(modifiers, cx) {
 7624                Some(ColumnarMode::FromSelection)
 7625            } else {
 7626                None
 7627            }
 7628        } else {
 7629            None
 7630        }
 7631    }
 7632
 7633    fn update_selection_mode(
 7634        &mut self,
 7635        modifiers: &Modifiers,
 7636        position_map: &PositionMap,
 7637        window: &mut Window,
 7638        cx: &mut Context<Self>,
 7639    ) {
 7640        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7641            return;
 7642        };
 7643        if self.selections.pending_anchor().is_none() {
 7644            return;
 7645        }
 7646
 7647        let mouse_position = window.mouse_position();
 7648        let point_for_position = position_map.point_for_position(mouse_position);
 7649        let position = point_for_position.previous_valid;
 7650
 7651        self.select(
 7652            SelectPhase::BeginColumnar {
 7653                position,
 7654                reset: false,
 7655                mode,
 7656                goal_column: point_for_position.exact_unclipped.column(),
 7657            },
 7658            window,
 7659            cx,
 7660        );
 7661    }
 7662
 7663    fn update_edit_prediction_preview(
 7664        &mut self,
 7665        modifiers: &Modifiers,
 7666        window: &mut Window,
 7667        cx: &mut Context<Self>,
 7668    ) {
 7669        let mut modifiers_held = false;
 7670        if let Some(accept_keystroke) = self
 7671            .accept_edit_prediction_keybind(false, window, cx)
 7672            .keystroke()
 7673        {
 7674            modifiers_held = modifiers_held
 7675                || (accept_keystroke.modifiers() == modifiers
 7676                    && accept_keystroke.modifiers().modified());
 7677        };
 7678        if let Some(accept_partial_keystroke) = self
 7679            .accept_edit_prediction_keybind(true, window, cx)
 7680            .keystroke()
 7681        {
 7682            modifiers_held = modifiers_held
 7683                || (accept_partial_keystroke.modifiers() == modifiers
 7684                    && accept_partial_keystroke.modifiers().modified());
 7685        }
 7686
 7687        if modifiers_held {
 7688            if matches!(
 7689                self.edit_prediction_preview,
 7690                EditPredictionPreview::Inactive { .. }
 7691            ) {
 7692                self.edit_prediction_preview = EditPredictionPreview::Active {
 7693                    previous_scroll_position: None,
 7694                    since: Instant::now(),
 7695                };
 7696
 7697                self.update_visible_edit_prediction(window, cx);
 7698                cx.notify();
 7699            }
 7700        } else if let EditPredictionPreview::Active {
 7701            previous_scroll_position,
 7702            since,
 7703        } = self.edit_prediction_preview
 7704        {
 7705            if let (Some(previous_scroll_position), Some(position_map)) =
 7706                (previous_scroll_position, self.last_position_map.as_ref())
 7707            {
 7708                self.set_scroll_position(
 7709                    previous_scroll_position
 7710                        .scroll_position(&position_map.snapshot.display_snapshot),
 7711                    window,
 7712                    cx,
 7713                );
 7714            }
 7715
 7716            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7717                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7718            };
 7719            self.clear_row_highlights::<EditPredictionPreview>();
 7720            self.update_visible_edit_prediction(window, cx);
 7721            cx.notify();
 7722        }
 7723    }
 7724
 7725    fn update_visible_edit_prediction(
 7726        &mut self,
 7727        _window: &mut Window,
 7728        cx: &mut Context<Self>,
 7729    ) -> Option<()> {
 7730        if DisableAiSettings::get_global(cx).disable_ai {
 7731            return None;
 7732        }
 7733
 7734        if self.ime_transaction.is_some() {
 7735            self.discard_edit_prediction(false, cx);
 7736            return None;
 7737        }
 7738
 7739        let selection = self.selections.newest_anchor();
 7740        let cursor = selection.head();
 7741        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7742        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7743        let excerpt_id = cursor.excerpt_id;
 7744
 7745        let show_in_menu = self.show_edit_predictions_in_menu();
 7746        let completions_menu_has_precedence = !show_in_menu
 7747            && (self.context_menu.borrow().is_some()
 7748                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7749
 7750        if completions_menu_has_precedence
 7751            || !offset_selection.is_empty()
 7752            || self
 7753                .active_edit_prediction
 7754                .as_ref()
 7755                .is_some_and(|completion| {
 7756                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7757                        return false;
 7758                    };
 7759                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7760                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7761                    !invalidation_range.contains(&offset_selection.head())
 7762                })
 7763        {
 7764            self.discard_edit_prediction(false, cx);
 7765            return None;
 7766        }
 7767
 7768        self.take_active_edit_prediction(cx);
 7769        let Some(provider) = self.edit_prediction_provider() else {
 7770            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7771            return None;
 7772        };
 7773
 7774        let (buffer, cursor_buffer_position) =
 7775            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7776
 7777        self.edit_prediction_settings =
 7778            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7779
 7780        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7781
 7782        if self.edit_prediction_indent_conflict {
 7783            let cursor_point = cursor.to_point(&multibuffer);
 7784
 7785            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7786
 7787            if let Some((_, indent)) = indents.iter().next()
 7788                && indent.len == cursor_point.column
 7789            {
 7790                self.edit_prediction_indent_conflict = false;
 7791            }
 7792        }
 7793
 7794        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7795
 7796        let (completion_id, edits, edit_preview) = match edit_prediction {
 7797            edit_prediction::EditPrediction::Local {
 7798                id,
 7799                edits,
 7800                edit_preview,
 7801            } => (id, edits, edit_preview),
 7802            edit_prediction::EditPrediction::Jump {
 7803                id,
 7804                snapshot,
 7805                target,
 7806            } => {
 7807                self.stale_edit_prediction_in_menu = None;
 7808                self.active_edit_prediction = Some(EditPredictionState {
 7809                    inlay_ids: vec![],
 7810                    completion: EditPrediction::MoveOutside { snapshot, target },
 7811                    completion_id: id,
 7812                    invalidation_range: None,
 7813                });
 7814                cx.notify();
 7815                return Some(());
 7816            }
 7817        };
 7818
 7819        let edits = edits
 7820            .into_iter()
 7821            .flat_map(|(range, new_text)| {
 7822                Some((
 7823                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7824                    new_text,
 7825                ))
 7826            })
 7827            .collect::<Vec<_>>();
 7828        if edits.is_empty() {
 7829            return None;
 7830        }
 7831
 7832        let first_edit_start = edits.first().unwrap().0.start;
 7833        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7834        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7835
 7836        let last_edit_end = edits.last().unwrap().0.end;
 7837        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7838        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7839
 7840        let cursor_row = cursor.to_point(&multibuffer).row;
 7841
 7842        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7843
 7844        let mut inlay_ids = Vec::new();
 7845        let invalidation_row_range;
 7846        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7847            Some(cursor_row..edit_end_row)
 7848        } else if cursor_row > edit_end_row {
 7849            Some(edit_start_row..cursor_row)
 7850        } else {
 7851            None
 7852        };
 7853        let supports_jump = self
 7854            .edit_prediction_provider
 7855            .as_ref()
 7856            .map(|provider| provider.provider.supports_jump_to_edit())
 7857            .unwrap_or(true);
 7858
 7859        let is_move = supports_jump
 7860            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7861        let completion = if is_move {
 7862            invalidation_row_range =
 7863                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7864            let target = first_edit_start;
 7865            EditPrediction::MoveWithin { target, snapshot }
 7866        } else {
 7867            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7868                && !self.edit_predictions_hidden_for_vim_mode;
 7869
 7870            if show_completions_in_buffer {
 7871                if edits
 7872                    .iter()
 7873                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7874                {
 7875                    let mut inlays = Vec::new();
 7876                    for (range, new_text) in &edits {
 7877                        let inlay = Inlay::edit_prediction(
 7878                            post_inc(&mut self.next_inlay_id),
 7879                            range.start,
 7880                            new_text.as_str(),
 7881                        );
 7882                        inlay_ids.push(inlay.id);
 7883                        inlays.push(inlay);
 7884                    }
 7885
 7886                    self.splice_inlays(&[], inlays, cx);
 7887                } else {
 7888                    let background_color = cx.theme().status().deleted_background;
 7889                    self.highlight_text::<EditPredictionHighlight>(
 7890                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7891                        HighlightStyle {
 7892                            background_color: Some(background_color),
 7893                            ..Default::default()
 7894                        },
 7895                        cx,
 7896                    );
 7897                }
 7898            }
 7899
 7900            invalidation_row_range = edit_start_row..edit_end_row;
 7901
 7902            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7903                if provider.show_tab_accept_marker() {
 7904                    EditDisplayMode::TabAccept
 7905                } else {
 7906                    EditDisplayMode::Inline
 7907                }
 7908            } else {
 7909                EditDisplayMode::DiffPopover
 7910            };
 7911
 7912            EditPrediction::Edit {
 7913                edits,
 7914                edit_preview,
 7915                display_mode,
 7916                snapshot,
 7917            }
 7918        };
 7919
 7920        let invalidation_range = multibuffer
 7921            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7922            ..multibuffer.anchor_after(Point::new(
 7923                invalidation_row_range.end,
 7924                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7925            ));
 7926
 7927        self.stale_edit_prediction_in_menu = None;
 7928        self.active_edit_prediction = Some(EditPredictionState {
 7929            inlay_ids,
 7930            completion,
 7931            completion_id,
 7932            invalidation_range: Some(invalidation_range),
 7933        });
 7934
 7935        cx.notify();
 7936
 7937        Some(())
 7938    }
 7939
 7940    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7941        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7942    }
 7943
 7944    fn clear_tasks(&mut self) {
 7945        self.tasks.clear()
 7946    }
 7947
 7948    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7949        if self.tasks.insert(key, value).is_some() {
 7950            // This case should hopefully be rare, but just in case...
 7951            log::error!(
 7952                "multiple different run targets found on a single line, only the last target will be rendered"
 7953            )
 7954        }
 7955    }
 7956
 7957    /// Get all display points of breakpoints that will be rendered within editor
 7958    ///
 7959    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7960    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7961    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7962    fn active_breakpoints(
 7963        &self,
 7964        range: Range<DisplayRow>,
 7965        window: &mut Window,
 7966        cx: &mut Context<Self>,
 7967    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7968        let mut breakpoint_display_points = HashMap::default();
 7969
 7970        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7971            return breakpoint_display_points;
 7972        };
 7973
 7974        let snapshot = self.snapshot(window, cx);
 7975
 7976        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 7977        let Some(project) = self.project() else {
 7978            return breakpoint_display_points;
 7979        };
 7980
 7981        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7982            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7983
 7984        for (buffer_snapshot, range, excerpt_id) in
 7985            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7986        {
 7987            let Some(buffer) = project
 7988                .read(cx)
 7989                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7990            else {
 7991                continue;
 7992            };
 7993            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7994                &buffer,
 7995                Some(
 7996                    buffer_snapshot.anchor_before(range.start)
 7997                        ..buffer_snapshot.anchor_after(range.end),
 7998                ),
 7999                buffer_snapshot,
 8000                cx,
 8001            );
 8002            for (breakpoint, state) in breakpoints {
 8003                let multi_buffer_anchor =
 8004                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8005                let position = multi_buffer_anchor
 8006                    .to_point(&multi_buffer_snapshot)
 8007                    .to_display_point(&snapshot);
 8008
 8009                breakpoint_display_points.insert(
 8010                    position.row(),
 8011                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8012                );
 8013            }
 8014        }
 8015
 8016        breakpoint_display_points
 8017    }
 8018
 8019    fn breakpoint_context_menu(
 8020        &self,
 8021        anchor: Anchor,
 8022        window: &mut Window,
 8023        cx: &mut Context<Self>,
 8024    ) -> Entity<ui::ContextMenu> {
 8025        let weak_editor = cx.weak_entity();
 8026        let focus_handle = self.focus_handle(cx);
 8027
 8028        let row = self
 8029            .buffer
 8030            .read(cx)
 8031            .snapshot(cx)
 8032            .summary_for_anchor::<Point>(&anchor)
 8033            .row;
 8034
 8035        let breakpoint = self
 8036            .breakpoint_at_row(row, window, cx)
 8037            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8038
 8039        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8040            "Edit Log Breakpoint"
 8041        } else {
 8042            "Set Log Breakpoint"
 8043        };
 8044
 8045        let condition_breakpoint_msg = if breakpoint
 8046            .as_ref()
 8047            .is_some_and(|bp| bp.1.condition.is_some())
 8048        {
 8049            "Edit Condition Breakpoint"
 8050        } else {
 8051            "Set Condition Breakpoint"
 8052        };
 8053
 8054        let hit_condition_breakpoint_msg = if breakpoint
 8055            .as_ref()
 8056            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8057        {
 8058            "Edit Hit Condition Breakpoint"
 8059        } else {
 8060            "Set Hit Condition Breakpoint"
 8061        };
 8062
 8063        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8064            "Unset Breakpoint"
 8065        } else {
 8066            "Set Breakpoint"
 8067        };
 8068
 8069        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8070
 8071        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8072            BreakpointState::Enabled => Some("Disable"),
 8073            BreakpointState::Disabled => Some("Enable"),
 8074        });
 8075
 8076        let (anchor, breakpoint) =
 8077            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8078
 8079        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8080            menu.on_blur_subscription(Subscription::new(|| {}))
 8081                .context(focus_handle)
 8082                .when(run_to_cursor, |this| {
 8083                    let weak_editor = weak_editor.clone();
 8084                    this.entry("Run to cursor", None, move |window, cx| {
 8085                        weak_editor
 8086                            .update(cx, |editor, cx| {
 8087                                editor.change_selections(
 8088                                    SelectionEffects::no_scroll(),
 8089                                    window,
 8090                                    cx,
 8091                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8092                                );
 8093                            })
 8094                            .ok();
 8095
 8096                        window.dispatch_action(Box::new(RunToCursor), cx);
 8097                    })
 8098                    .separator()
 8099                })
 8100                .when_some(toggle_state_msg, |this, msg| {
 8101                    this.entry(msg, None, {
 8102                        let weak_editor = weak_editor.clone();
 8103                        let breakpoint = breakpoint.clone();
 8104                        move |_window, cx| {
 8105                            weak_editor
 8106                                .update(cx, |this, cx| {
 8107                                    this.edit_breakpoint_at_anchor(
 8108                                        anchor,
 8109                                        breakpoint.as_ref().clone(),
 8110                                        BreakpointEditAction::InvertState,
 8111                                        cx,
 8112                                    );
 8113                                })
 8114                                .log_err();
 8115                        }
 8116                    })
 8117                })
 8118                .entry(set_breakpoint_msg, None, {
 8119                    let weak_editor = weak_editor.clone();
 8120                    let breakpoint = breakpoint.clone();
 8121                    move |_window, cx| {
 8122                        weak_editor
 8123                            .update(cx, |this, cx| {
 8124                                this.edit_breakpoint_at_anchor(
 8125                                    anchor,
 8126                                    breakpoint.as_ref().clone(),
 8127                                    BreakpointEditAction::Toggle,
 8128                                    cx,
 8129                                );
 8130                            })
 8131                            .log_err();
 8132                    }
 8133                })
 8134                .entry(log_breakpoint_msg, None, {
 8135                    let breakpoint = breakpoint.clone();
 8136                    let weak_editor = weak_editor.clone();
 8137                    move |window, cx| {
 8138                        weak_editor
 8139                            .update(cx, |this, cx| {
 8140                                this.add_edit_breakpoint_block(
 8141                                    anchor,
 8142                                    breakpoint.as_ref(),
 8143                                    BreakpointPromptEditAction::Log,
 8144                                    window,
 8145                                    cx,
 8146                                );
 8147                            })
 8148                            .log_err();
 8149                    }
 8150                })
 8151                .entry(condition_breakpoint_msg, None, {
 8152                    let breakpoint = breakpoint.clone();
 8153                    let weak_editor = weak_editor.clone();
 8154                    move |window, cx| {
 8155                        weak_editor
 8156                            .update(cx, |this, cx| {
 8157                                this.add_edit_breakpoint_block(
 8158                                    anchor,
 8159                                    breakpoint.as_ref(),
 8160                                    BreakpointPromptEditAction::Condition,
 8161                                    window,
 8162                                    cx,
 8163                                );
 8164                            })
 8165                            .log_err();
 8166                    }
 8167                })
 8168                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8169                    weak_editor
 8170                        .update(cx, |this, cx| {
 8171                            this.add_edit_breakpoint_block(
 8172                                anchor,
 8173                                breakpoint.as_ref(),
 8174                                BreakpointPromptEditAction::HitCondition,
 8175                                window,
 8176                                cx,
 8177                            );
 8178                        })
 8179                        .log_err();
 8180                })
 8181        })
 8182    }
 8183
 8184    fn render_breakpoint(
 8185        &self,
 8186        position: Anchor,
 8187        row: DisplayRow,
 8188        breakpoint: &Breakpoint,
 8189        state: Option<BreakpointSessionState>,
 8190        cx: &mut Context<Self>,
 8191    ) -> IconButton {
 8192        let is_rejected = state.is_some_and(|s| !s.verified);
 8193        // Is it a breakpoint that shows up when hovering over gutter?
 8194        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8195            (false, false),
 8196            |PhantomBreakpointIndicator {
 8197                 is_active,
 8198                 display_row,
 8199                 collides_with_existing_breakpoint,
 8200             }| {
 8201                (
 8202                    is_active && display_row == row,
 8203                    collides_with_existing_breakpoint,
 8204                )
 8205            },
 8206        );
 8207
 8208        let (color, icon) = {
 8209            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8210                (false, false) => ui::IconName::DebugBreakpoint,
 8211                (true, false) => ui::IconName::DebugLogBreakpoint,
 8212                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8213                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8214            };
 8215
 8216            let color = if is_phantom {
 8217                Color::Hint
 8218            } else if is_rejected {
 8219                Color::Disabled
 8220            } else {
 8221                Color::Debugger
 8222            };
 8223
 8224            (color, icon)
 8225        };
 8226
 8227        let breakpoint = Arc::from(breakpoint.clone());
 8228
 8229        let alt_as_text = gpui::Keystroke {
 8230            modifiers: Modifiers::secondary_key(),
 8231            ..Default::default()
 8232        };
 8233        let primary_action_text = if breakpoint.is_disabled() {
 8234            "Enable breakpoint"
 8235        } else if is_phantom && !collides_with_existing {
 8236            "Set breakpoint"
 8237        } else {
 8238            "Unset breakpoint"
 8239        };
 8240        let focus_handle = self.focus_handle.clone();
 8241
 8242        let meta = if is_rejected {
 8243            SharedString::from("No executable code is associated with this line.")
 8244        } else if collides_with_existing && !breakpoint.is_disabled() {
 8245            SharedString::from(format!(
 8246                "{alt_as_text}-click to disable,\nright-click for more options."
 8247            ))
 8248        } else {
 8249            SharedString::from("Right-click for more options.")
 8250        };
 8251        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8252            .icon_size(IconSize::XSmall)
 8253            .size(ui::ButtonSize::None)
 8254            .when(is_rejected, |this| {
 8255                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8256            })
 8257            .icon_color(color)
 8258            .style(ButtonStyle::Transparent)
 8259            .on_click(cx.listener({
 8260                move |editor, event: &ClickEvent, window, cx| {
 8261                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8262                        BreakpointEditAction::InvertState
 8263                    } else {
 8264                        BreakpointEditAction::Toggle
 8265                    };
 8266
 8267                    window.focus(&editor.focus_handle(cx));
 8268                    editor.edit_breakpoint_at_anchor(
 8269                        position,
 8270                        breakpoint.as_ref().clone(),
 8271                        edit_action,
 8272                        cx,
 8273                    );
 8274                }
 8275            }))
 8276            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8277                editor.set_breakpoint_context_menu(
 8278                    row,
 8279                    Some(position),
 8280                    event.position(),
 8281                    window,
 8282                    cx,
 8283                );
 8284            }))
 8285            .tooltip(move |_window, cx| {
 8286                Tooltip::with_meta_in(
 8287                    primary_action_text,
 8288                    Some(&ToggleBreakpoint),
 8289                    meta.clone(),
 8290                    &focus_handle,
 8291                    cx,
 8292                )
 8293            })
 8294    }
 8295
 8296    fn build_tasks_context(
 8297        project: &Entity<Project>,
 8298        buffer: &Entity<Buffer>,
 8299        buffer_row: u32,
 8300        tasks: &Arc<RunnableTasks>,
 8301        cx: &mut Context<Self>,
 8302    ) -> Task<Option<task::TaskContext>> {
 8303        let position = Point::new(buffer_row, tasks.column);
 8304        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8305        let location = Location {
 8306            buffer: buffer.clone(),
 8307            range: range_start..range_start,
 8308        };
 8309        // Fill in the environmental variables from the tree-sitter captures
 8310        let mut captured_task_variables = TaskVariables::default();
 8311        for (capture_name, value) in tasks.extra_variables.clone() {
 8312            captured_task_variables.insert(
 8313                task::VariableName::Custom(capture_name.into()),
 8314                value.clone(),
 8315            );
 8316        }
 8317        project.update(cx, |project, cx| {
 8318            project.task_store().update(cx, |task_store, cx| {
 8319                task_store.task_context_for_location(captured_task_variables, location, cx)
 8320            })
 8321        })
 8322    }
 8323
 8324    pub fn spawn_nearest_task(
 8325        &mut self,
 8326        action: &SpawnNearestTask,
 8327        window: &mut Window,
 8328        cx: &mut Context<Self>,
 8329    ) {
 8330        let Some((workspace, _)) = self.workspace.clone() else {
 8331            return;
 8332        };
 8333        let Some(project) = self.project.clone() else {
 8334            return;
 8335        };
 8336
 8337        // Try to find a closest, enclosing node using tree-sitter that has a task
 8338        let Some((buffer, buffer_row, tasks)) = self
 8339            .find_enclosing_node_task(cx)
 8340            // Or find the task that's closest in row-distance.
 8341            .or_else(|| self.find_closest_task(cx))
 8342        else {
 8343            return;
 8344        };
 8345
 8346        let reveal_strategy = action.reveal;
 8347        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8348        cx.spawn_in(window, async move |_, cx| {
 8349            let context = task_context.await?;
 8350            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8351
 8352            let resolved = &mut resolved_task.resolved;
 8353            resolved.reveal = reveal_strategy;
 8354
 8355            workspace
 8356                .update_in(cx, |workspace, window, cx| {
 8357                    workspace.schedule_resolved_task(
 8358                        task_source_kind,
 8359                        resolved_task,
 8360                        false,
 8361                        window,
 8362                        cx,
 8363                    );
 8364                })
 8365                .ok()
 8366        })
 8367        .detach();
 8368    }
 8369
 8370    fn find_closest_task(
 8371        &mut self,
 8372        cx: &mut Context<Self>,
 8373    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8374        let cursor_row = self
 8375            .selections
 8376            .newest_adjusted(&self.display_snapshot(cx))
 8377            .head()
 8378            .row;
 8379
 8380        let ((buffer_id, row), tasks) = self
 8381            .tasks
 8382            .iter()
 8383            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8384
 8385        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8386        let tasks = Arc::new(tasks.to_owned());
 8387        Some((buffer, *row, tasks))
 8388    }
 8389
 8390    fn find_enclosing_node_task(
 8391        &mut self,
 8392        cx: &mut Context<Self>,
 8393    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8394        let snapshot = self.buffer.read(cx).snapshot(cx);
 8395        let offset = self
 8396            .selections
 8397            .newest::<usize>(&self.display_snapshot(cx))
 8398            .head();
 8399        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8400        let buffer_id = excerpt.buffer().remote_id();
 8401
 8402        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8403        let mut cursor = layer.node().walk();
 8404
 8405        while cursor.goto_first_child_for_byte(offset).is_some() {
 8406            if cursor.node().end_byte() == offset {
 8407                cursor.goto_next_sibling();
 8408            }
 8409        }
 8410
 8411        // Ascend to the smallest ancestor that contains the range and has a task.
 8412        loop {
 8413            let node = cursor.node();
 8414            let node_range = node.byte_range();
 8415            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8416
 8417            // Check if this node contains our offset
 8418            if node_range.start <= offset && node_range.end >= offset {
 8419                // If it contains offset, check for task
 8420                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8421                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8422                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8423                }
 8424            }
 8425
 8426            if !cursor.goto_parent() {
 8427                break;
 8428            }
 8429        }
 8430        None
 8431    }
 8432
 8433    fn render_run_indicator(
 8434        &self,
 8435        _style: &EditorStyle,
 8436        is_active: bool,
 8437        row: DisplayRow,
 8438        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8439        cx: &mut Context<Self>,
 8440    ) -> IconButton {
 8441        let color = Color::Muted;
 8442        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8443
 8444        IconButton::new(
 8445            ("run_indicator", row.0 as usize),
 8446            ui::IconName::PlayOutlined,
 8447        )
 8448        .shape(ui::IconButtonShape::Square)
 8449        .icon_size(IconSize::XSmall)
 8450        .icon_color(color)
 8451        .toggle_state(is_active)
 8452        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8453            let quick_launch = match e {
 8454                ClickEvent::Keyboard(_) => true,
 8455                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8456            };
 8457
 8458            window.focus(&editor.focus_handle(cx));
 8459            editor.toggle_code_actions(
 8460                &ToggleCodeActions {
 8461                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8462                    quick_launch,
 8463                },
 8464                window,
 8465                cx,
 8466            );
 8467        }))
 8468        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8469            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8470        }))
 8471    }
 8472
 8473    pub fn context_menu_visible(&self) -> bool {
 8474        !self.edit_prediction_preview_is_active()
 8475            && self
 8476                .context_menu
 8477                .borrow()
 8478                .as_ref()
 8479                .is_some_and(|menu| menu.visible())
 8480    }
 8481
 8482    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8483        self.context_menu
 8484            .borrow()
 8485            .as_ref()
 8486            .map(|menu| menu.origin())
 8487    }
 8488
 8489    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8490        self.context_menu_options = Some(options);
 8491    }
 8492
 8493    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8494    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8495
 8496    fn render_edit_prediction_popover(
 8497        &mut self,
 8498        text_bounds: &Bounds<Pixels>,
 8499        content_origin: gpui::Point<Pixels>,
 8500        right_margin: Pixels,
 8501        editor_snapshot: &EditorSnapshot,
 8502        visible_row_range: Range<DisplayRow>,
 8503        scroll_top: ScrollOffset,
 8504        scroll_bottom: ScrollOffset,
 8505        line_layouts: &[LineWithInvisibles],
 8506        line_height: Pixels,
 8507        scroll_position: gpui::Point<ScrollOffset>,
 8508        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8509        newest_selection_head: Option<DisplayPoint>,
 8510        editor_width: Pixels,
 8511        style: &EditorStyle,
 8512        window: &mut Window,
 8513        cx: &mut App,
 8514    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8515        if self.mode().is_minimap() {
 8516            return None;
 8517        }
 8518        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8519
 8520        if self.edit_prediction_visible_in_cursor_popover(true) {
 8521            return None;
 8522        }
 8523
 8524        match &active_edit_prediction.completion {
 8525            EditPrediction::MoveWithin { target, .. } => {
 8526                let target_display_point = target.to_display_point(editor_snapshot);
 8527
 8528                if self.edit_prediction_requires_modifier() {
 8529                    if !self.edit_prediction_preview_is_active() {
 8530                        return None;
 8531                    }
 8532
 8533                    self.render_edit_prediction_modifier_jump_popover(
 8534                        text_bounds,
 8535                        content_origin,
 8536                        visible_row_range,
 8537                        line_layouts,
 8538                        line_height,
 8539                        scroll_pixel_position,
 8540                        newest_selection_head,
 8541                        target_display_point,
 8542                        window,
 8543                        cx,
 8544                    )
 8545                } else {
 8546                    self.render_edit_prediction_eager_jump_popover(
 8547                        text_bounds,
 8548                        content_origin,
 8549                        editor_snapshot,
 8550                        visible_row_range,
 8551                        scroll_top,
 8552                        scroll_bottom,
 8553                        line_height,
 8554                        scroll_pixel_position,
 8555                        target_display_point,
 8556                        editor_width,
 8557                        window,
 8558                        cx,
 8559                    )
 8560                }
 8561            }
 8562            EditPrediction::Edit {
 8563                display_mode: EditDisplayMode::Inline,
 8564                ..
 8565            } => None,
 8566            EditPrediction::Edit {
 8567                display_mode: EditDisplayMode::TabAccept,
 8568                edits,
 8569                ..
 8570            } => {
 8571                let range = &edits.first()?.0;
 8572                let target_display_point = range.end.to_display_point(editor_snapshot);
 8573
 8574                self.render_edit_prediction_end_of_line_popover(
 8575                    "Accept",
 8576                    editor_snapshot,
 8577                    visible_row_range,
 8578                    target_display_point,
 8579                    line_height,
 8580                    scroll_pixel_position,
 8581                    content_origin,
 8582                    editor_width,
 8583                    window,
 8584                    cx,
 8585                )
 8586            }
 8587            EditPrediction::Edit {
 8588                edits,
 8589                edit_preview,
 8590                display_mode: EditDisplayMode::DiffPopover,
 8591                snapshot,
 8592            } => self.render_edit_prediction_diff_popover(
 8593                text_bounds,
 8594                content_origin,
 8595                right_margin,
 8596                editor_snapshot,
 8597                visible_row_range,
 8598                line_layouts,
 8599                line_height,
 8600                scroll_position,
 8601                scroll_pixel_position,
 8602                newest_selection_head,
 8603                editor_width,
 8604                style,
 8605                edits,
 8606                edit_preview,
 8607                snapshot,
 8608                window,
 8609                cx,
 8610            ),
 8611            EditPrediction::MoveOutside { snapshot, .. } => {
 8612                let file_name = snapshot
 8613                    .file()
 8614                    .map(|file| file.file_name(cx))
 8615                    .unwrap_or("untitled");
 8616                let mut element = self
 8617                    .render_edit_prediction_line_popover(
 8618                        format!("Jump to {file_name}"),
 8619                        Some(IconName::ZedPredict),
 8620                        window,
 8621                        cx,
 8622                    )
 8623                    .into_any();
 8624
 8625                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8626                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8627                let origin_y = text_bounds.size.height - size.height - px(30.);
 8628                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8629                element.prepaint_at(origin, window, cx);
 8630
 8631                Some((element, origin))
 8632            }
 8633        }
 8634    }
 8635
 8636    fn render_edit_prediction_modifier_jump_popover(
 8637        &mut self,
 8638        text_bounds: &Bounds<Pixels>,
 8639        content_origin: gpui::Point<Pixels>,
 8640        visible_row_range: Range<DisplayRow>,
 8641        line_layouts: &[LineWithInvisibles],
 8642        line_height: Pixels,
 8643        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8644        newest_selection_head: Option<DisplayPoint>,
 8645        target_display_point: DisplayPoint,
 8646        window: &mut Window,
 8647        cx: &mut App,
 8648    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8649        let scrolled_content_origin =
 8650            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8651
 8652        const SCROLL_PADDING_Y: Pixels = px(12.);
 8653
 8654        if target_display_point.row() < visible_row_range.start {
 8655            return self.render_edit_prediction_scroll_popover(
 8656                |_| SCROLL_PADDING_Y,
 8657                IconName::ArrowUp,
 8658                visible_row_range,
 8659                line_layouts,
 8660                newest_selection_head,
 8661                scrolled_content_origin,
 8662                window,
 8663                cx,
 8664            );
 8665        } else if target_display_point.row() >= visible_row_range.end {
 8666            return self.render_edit_prediction_scroll_popover(
 8667                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8668                IconName::ArrowDown,
 8669                visible_row_range,
 8670                line_layouts,
 8671                newest_selection_head,
 8672                scrolled_content_origin,
 8673                window,
 8674                cx,
 8675            );
 8676        }
 8677
 8678        const POLE_WIDTH: Pixels = px(2.);
 8679
 8680        let line_layout =
 8681            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8682        let target_column = target_display_point.column() as usize;
 8683
 8684        let target_x = line_layout.x_for_index(target_column);
 8685        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8686            - scroll_pixel_position.y;
 8687
 8688        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8689
 8690        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8691        border_color.l += 0.001;
 8692
 8693        let mut element = v_flex()
 8694            .items_end()
 8695            .when(flag_on_right, |el| el.items_start())
 8696            .child(if flag_on_right {
 8697                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8698                    .rounded_bl(px(0.))
 8699                    .rounded_tl(px(0.))
 8700                    .border_l_2()
 8701                    .border_color(border_color)
 8702            } else {
 8703                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8704                    .rounded_br(px(0.))
 8705                    .rounded_tr(px(0.))
 8706                    .border_r_2()
 8707                    .border_color(border_color)
 8708            })
 8709            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8710            .into_any();
 8711
 8712        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8713
 8714        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8715            - point(
 8716                if flag_on_right {
 8717                    POLE_WIDTH
 8718                } else {
 8719                    size.width - POLE_WIDTH
 8720                },
 8721                size.height - line_height,
 8722            );
 8723
 8724        origin.x = origin.x.max(content_origin.x);
 8725
 8726        element.prepaint_at(origin, window, cx);
 8727
 8728        Some((element, origin))
 8729    }
 8730
 8731    fn render_edit_prediction_scroll_popover(
 8732        &mut self,
 8733        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8734        scroll_icon: IconName,
 8735        visible_row_range: Range<DisplayRow>,
 8736        line_layouts: &[LineWithInvisibles],
 8737        newest_selection_head: Option<DisplayPoint>,
 8738        scrolled_content_origin: gpui::Point<Pixels>,
 8739        window: &mut Window,
 8740        cx: &mut App,
 8741    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8742        let mut element = self
 8743            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8744            .into_any();
 8745
 8746        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8747
 8748        let cursor = newest_selection_head?;
 8749        let cursor_row_layout =
 8750            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8751        let cursor_column = cursor.column() as usize;
 8752
 8753        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8754
 8755        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8756
 8757        element.prepaint_at(origin, window, cx);
 8758        Some((element, origin))
 8759    }
 8760
 8761    fn render_edit_prediction_eager_jump_popover(
 8762        &mut self,
 8763        text_bounds: &Bounds<Pixels>,
 8764        content_origin: gpui::Point<Pixels>,
 8765        editor_snapshot: &EditorSnapshot,
 8766        visible_row_range: Range<DisplayRow>,
 8767        scroll_top: ScrollOffset,
 8768        scroll_bottom: ScrollOffset,
 8769        line_height: Pixels,
 8770        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8771        target_display_point: DisplayPoint,
 8772        editor_width: Pixels,
 8773        window: &mut Window,
 8774        cx: &mut App,
 8775    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8776        if target_display_point.row().as_f64() < scroll_top {
 8777            let mut element = self
 8778                .render_edit_prediction_line_popover(
 8779                    "Jump to Edit",
 8780                    Some(IconName::ArrowUp),
 8781                    window,
 8782                    cx,
 8783                )
 8784                .into_any();
 8785
 8786            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8787            let offset = point(
 8788                (text_bounds.size.width - size.width) / 2.,
 8789                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8790            );
 8791
 8792            let origin = text_bounds.origin + offset;
 8793            element.prepaint_at(origin, window, cx);
 8794            Some((element, origin))
 8795        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8796            let mut element = self
 8797                .render_edit_prediction_line_popover(
 8798                    "Jump to Edit",
 8799                    Some(IconName::ArrowDown),
 8800                    window,
 8801                    cx,
 8802                )
 8803                .into_any();
 8804
 8805            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8806            let offset = point(
 8807                (text_bounds.size.width - size.width) / 2.,
 8808                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8809            );
 8810
 8811            let origin = text_bounds.origin + offset;
 8812            element.prepaint_at(origin, window, cx);
 8813            Some((element, origin))
 8814        } else {
 8815            self.render_edit_prediction_end_of_line_popover(
 8816                "Jump to Edit",
 8817                editor_snapshot,
 8818                visible_row_range,
 8819                target_display_point,
 8820                line_height,
 8821                scroll_pixel_position,
 8822                content_origin,
 8823                editor_width,
 8824                window,
 8825                cx,
 8826            )
 8827        }
 8828    }
 8829
 8830    fn render_edit_prediction_end_of_line_popover(
 8831        self: &mut Editor,
 8832        label: &'static str,
 8833        editor_snapshot: &EditorSnapshot,
 8834        visible_row_range: Range<DisplayRow>,
 8835        target_display_point: DisplayPoint,
 8836        line_height: Pixels,
 8837        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8838        content_origin: gpui::Point<Pixels>,
 8839        editor_width: Pixels,
 8840        window: &mut Window,
 8841        cx: &mut App,
 8842    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8843        let target_line_end = DisplayPoint::new(
 8844            target_display_point.row(),
 8845            editor_snapshot.line_len(target_display_point.row()),
 8846        );
 8847
 8848        let mut element = self
 8849            .render_edit_prediction_line_popover(label, None, window, cx)
 8850            .into_any();
 8851
 8852        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8853
 8854        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8855
 8856        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8857        let mut origin = start_point
 8858            + line_origin
 8859            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8860        origin.x = origin.x.max(content_origin.x);
 8861
 8862        let max_x = content_origin.x + editor_width - size.width;
 8863
 8864        if origin.x > max_x {
 8865            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8866
 8867            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8868                origin.y += offset;
 8869                IconName::ArrowUp
 8870            } else {
 8871                origin.y -= offset;
 8872                IconName::ArrowDown
 8873            };
 8874
 8875            element = self
 8876                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8877                .into_any();
 8878
 8879            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8880
 8881            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8882        }
 8883
 8884        element.prepaint_at(origin, window, cx);
 8885        Some((element, origin))
 8886    }
 8887
 8888    fn render_edit_prediction_diff_popover(
 8889        self: &Editor,
 8890        text_bounds: &Bounds<Pixels>,
 8891        content_origin: gpui::Point<Pixels>,
 8892        right_margin: Pixels,
 8893        editor_snapshot: &EditorSnapshot,
 8894        visible_row_range: Range<DisplayRow>,
 8895        line_layouts: &[LineWithInvisibles],
 8896        line_height: Pixels,
 8897        scroll_position: gpui::Point<ScrollOffset>,
 8898        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8899        newest_selection_head: Option<DisplayPoint>,
 8900        editor_width: Pixels,
 8901        style: &EditorStyle,
 8902        edits: &Vec<(Range<Anchor>, String)>,
 8903        edit_preview: &Option<language::EditPreview>,
 8904        snapshot: &language::BufferSnapshot,
 8905        window: &mut Window,
 8906        cx: &mut App,
 8907    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8908        let edit_start = edits
 8909            .first()
 8910            .unwrap()
 8911            .0
 8912            .start
 8913            .to_display_point(editor_snapshot);
 8914        let edit_end = edits
 8915            .last()
 8916            .unwrap()
 8917            .0
 8918            .end
 8919            .to_display_point(editor_snapshot);
 8920
 8921        let is_visible = visible_row_range.contains(&edit_start.row())
 8922            || visible_row_range.contains(&edit_end.row());
 8923        if !is_visible {
 8924            return None;
 8925        }
 8926
 8927        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8928            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8929        } else {
 8930            // Fallback for providers without edit_preview
 8931            crate::edit_prediction_fallback_text(edits, cx)
 8932        };
 8933
 8934        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8935        let line_count = highlighted_edits.text.lines().count();
 8936
 8937        const BORDER_WIDTH: Pixels = px(1.);
 8938
 8939        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8940        let has_keybind = keybind.is_some();
 8941
 8942        let mut element = h_flex()
 8943            .items_start()
 8944            .child(
 8945                h_flex()
 8946                    .bg(cx.theme().colors().editor_background)
 8947                    .border(BORDER_WIDTH)
 8948                    .shadow_xs()
 8949                    .border_color(cx.theme().colors().border)
 8950                    .rounded_l_lg()
 8951                    .when(line_count > 1, |el| el.rounded_br_lg())
 8952                    .pr_1()
 8953                    .child(styled_text),
 8954            )
 8955            .child(
 8956                h_flex()
 8957                    .h(line_height + BORDER_WIDTH * 2.)
 8958                    .px_1p5()
 8959                    .gap_1()
 8960                    // Workaround: For some reason, there's a gap if we don't do this
 8961                    .ml(-BORDER_WIDTH)
 8962                    .shadow(vec![gpui::BoxShadow {
 8963                        color: gpui::black().opacity(0.05),
 8964                        offset: point(px(1.), px(1.)),
 8965                        blur_radius: px(2.),
 8966                        spread_radius: px(0.),
 8967                    }])
 8968                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8969                    .border(BORDER_WIDTH)
 8970                    .border_color(cx.theme().colors().border)
 8971                    .rounded_r_lg()
 8972                    .id("edit_prediction_diff_popover_keybind")
 8973                    .when(!has_keybind, |el| {
 8974                        let status_colors = cx.theme().status();
 8975
 8976                        el.bg(status_colors.error_background)
 8977                            .border_color(status_colors.error.opacity(0.6))
 8978                            .child(Icon::new(IconName::Info).color(Color::Error))
 8979                            .cursor_default()
 8980                            .hoverable_tooltip(move |_window, cx| {
 8981                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8982                            })
 8983                    })
 8984                    .children(keybind),
 8985            )
 8986            .into_any();
 8987
 8988        let longest_row =
 8989            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8990        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8991            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8992        } else {
 8993            layout_line(
 8994                longest_row,
 8995                editor_snapshot,
 8996                style,
 8997                editor_width,
 8998                |_| false,
 8999                window,
 9000                cx,
 9001            )
 9002            .width
 9003        };
 9004
 9005        let viewport_bounds =
 9006            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9007                right: -right_margin,
 9008                ..Default::default()
 9009            });
 9010
 9011        let x_after_longest = Pixels::from(
 9012            ScrollPixelOffset::from(
 9013                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9014            ) - scroll_pixel_position.x,
 9015        );
 9016
 9017        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9018
 9019        // Fully visible if it can be displayed within the window (allow overlapping other
 9020        // panes). However, this is only allowed if the popover starts within text_bounds.
 9021        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9022            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9023
 9024        let mut origin = if can_position_to_the_right {
 9025            point(
 9026                x_after_longest,
 9027                text_bounds.origin.y
 9028                    + Pixels::from(
 9029                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9030                            - scroll_pixel_position.y,
 9031                    ),
 9032            )
 9033        } else {
 9034            let cursor_row = newest_selection_head.map(|head| head.row());
 9035            let above_edit = edit_start
 9036                .row()
 9037                .0
 9038                .checked_sub(line_count as u32)
 9039                .map(DisplayRow);
 9040            let below_edit = Some(edit_end.row() + 1);
 9041            let above_cursor =
 9042                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9043            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9044
 9045            // Place the edit popover adjacent to the edit if there is a location
 9046            // available that is onscreen and does not obscure the cursor. Otherwise,
 9047            // place it adjacent to the cursor.
 9048            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9049                .into_iter()
 9050                .flatten()
 9051                .find(|&start_row| {
 9052                    let end_row = start_row + line_count as u32;
 9053                    visible_row_range.contains(&start_row)
 9054                        && visible_row_range.contains(&end_row)
 9055                        && cursor_row
 9056                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9057                })?;
 9058
 9059            content_origin
 9060                + point(
 9061                    Pixels::from(-scroll_pixel_position.x),
 9062                    Pixels::from(
 9063                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9064                    ),
 9065                )
 9066        };
 9067
 9068        origin.x -= BORDER_WIDTH;
 9069
 9070        window.defer_draw(element, origin, 1);
 9071
 9072        // Do not return an element, since it will already be drawn due to defer_draw.
 9073        None
 9074    }
 9075
 9076    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9077        px(30.)
 9078    }
 9079
 9080    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9081        if self.read_only(cx) {
 9082            cx.theme().players().read_only()
 9083        } else {
 9084            self.style.as_ref().unwrap().local_player
 9085        }
 9086    }
 9087
 9088    fn render_edit_prediction_accept_keybind(
 9089        &self,
 9090        window: &mut Window,
 9091        cx: &mut App,
 9092    ) -> Option<AnyElement> {
 9093        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9094        let accept_keystroke = accept_binding.keystroke()?;
 9095
 9096        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9097
 9098        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9099            Color::Accent
 9100        } else {
 9101            Color::Muted
 9102        };
 9103
 9104        h_flex()
 9105            .px_0p5()
 9106            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9107            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9108            .text_size(TextSize::XSmall.rems(cx))
 9109            .child(h_flex().children(ui::render_modifiers(
 9110                accept_keystroke.modifiers(),
 9111                PlatformStyle::platform(),
 9112                Some(modifiers_color),
 9113                Some(IconSize::XSmall.rems().into()),
 9114                true,
 9115            )))
 9116            .when(is_platform_style_mac, |parent| {
 9117                parent.child(accept_keystroke.key().to_string())
 9118            })
 9119            .when(!is_platform_style_mac, |parent| {
 9120                parent.child(
 9121                    Key::new(
 9122                        util::capitalize(accept_keystroke.key()),
 9123                        Some(Color::Default),
 9124                    )
 9125                    .size(Some(IconSize::XSmall.rems().into())),
 9126                )
 9127            })
 9128            .into_any()
 9129            .into()
 9130    }
 9131
 9132    fn render_edit_prediction_line_popover(
 9133        &self,
 9134        label: impl Into<SharedString>,
 9135        icon: Option<IconName>,
 9136        window: &mut Window,
 9137        cx: &mut App,
 9138    ) -> Stateful<Div> {
 9139        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9140
 9141        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9142        let has_keybind = keybind.is_some();
 9143
 9144        h_flex()
 9145            .id("ep-line-popover")
 9146            .py_0p5()
 9147            .pl_1()
 9148            .pr(padding_right)
 9149            .gap_1()
 9150            .rounded_md()
 9151            .border_1()
 9152            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9153            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9154            .shadow_xs()
 9155            .when(!has_keybind, |el| {
 9156                let status_colors = cx.theme().status();
 9157
 9158                el.bg(status_colors.error_background)
 9159                    .border_color(status_colors.error.opacity(0.6))
 9160                    .pl_2()
 9161                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9162                    .cursor_default()
 9163                    .hoverable_tooltip(move |_window, cx| {
 9164                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9165                    })
 9166            })
 9167            .children(keybind)
 9168            .child(
 9169                Label::new(label)
 9170                    .size(LabelSize::Small)
 9171                    .when(!has_keybind, |el| {
 9172                        el.color(cx.theme().status().error.into()).strikethrough()
 9173                    }),
 9174            )
 9175            .when(!has_keybind, |el| {
 9176                el.child(
 9177                    h_flex().ml_1().child(
 9178                        Icon::new(IconName::Info)
 9179                            .size(IconSize::Small)
 9180                            .color(cx.theme().status().error.into()),
 9181                    ),
 9182                )
 9183            })
 9184            .when_some(icon, |element, icon| {
 9185                element.child(
 9186                    div()
 9187                        .mt(px(1.5))
 9188                        .child(Icon::new(icon).size(IconSize::Small)),
 9189                )
 9190            })
 9191    }
 9192
 9193    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9194        let accent_color = cx.theme().colors().text_accent;
 9195        let editor_bg_color = cx.theme().colors().editor_background;
 9196        editor_bg_color.blend(accent_color.opacity(0.1))
 9197    }
 9198
 9199    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9200        let accent_color = cx.theme().colors().text_accent;
 9201        let editor_bg_color = cx.theme().colors().editor_background;
 9202        editor_bg_color.blend(accent_color.opacity(0.6))
 9203    }
 9204    fn get_prediction_provider_icon_name(
 9205        provider: &Option<RegisteredEditPredictionProvider>,
 9206    ) -> IconName {
 9207        match provider {
 9208            Some(provider) => match provider.provider.name() {
 9209                "copilot" => IconName::Copilot,
 9210                "supermaven" => IconName::Supermaven,
 9211                _ => IconName::ZedPredict,
 9212            },
 9213            None => IconName::ZedPredict,
 9214        }
 9215    }
 9216
 9217    fn render_edit_prediction_cursor_popover(
 9218        &self,
 9219        min_width: Pixels,
 9220        max_width: Pixels,
 9221        cursor_point: Point,
 9222        style: &EditorStyle,
 9223        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9224        _window: &Window,
 9225        cx: &mut Context<Editor>,
 9226    ) -> Option<AnyElement> {
 9227        let provider = self.edit_prediction_provider.as_ref()?;
 9228        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9229
 9230        let is_refreshing = provider.provider.is_refreshing(cx);
 9231
 9232        fn pending_completion_container(icon: IconName) -> Div {
 9233            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9234        }
 9235
 9236        let completion = match &self.active_edit_prediction {
 9237            Some(prediction) => {
 9238                if !self.has_visible_completions_menu() {
 9239                    const RADIUS: Pixels = px(6.);
 9240                    const BORDER_WIDTH: Pixels = px(1.);
 9241
 9242                    return Some(
 9243                        h_flex()
 9244                            .elevation_2(cx)
 9245                            .border(BORDER_WIDTH)
 9246                            .border_color(cx.theme().colors().border)
 9247                            .when(accept_keystroke.is_none(), |el| {
 9248                                el.border_color(cx.theme().status().error)
 9249                            })
 9250                            .rounded(RADIUS)
 9251                            .rounded_tl(px(0.))
 9252                            .overflow_hidden()
 9253                            .child(div().px_1p5().child(match &prediction.completion {
 9254                                EditPrediction::MoveWithin { target, snapshot } => {
 9255                                    use text::ToPoint as _;
 9256                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9257                                    {
 9258                                        Icon::new(IconName::ZedPredictDown)
 9259                                    } else {
 9260                                        Icon::new(IconName::ZedPredictUp)
 9261                                    }
 9262                                }
 9263                                EditPrediction::MoveOutside { .. } => {
 9264                                    // TODO [zeta2] custom icon for external jump?
 9265                                    Icon::new(provider_icon)
 9266                                }
 9267                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9268                            }))
 9269                            .child(
 9270                                h_flex()
 9271                                    .gap_1()
 9272                                    .py_1()
 9273                                    .px_2()
 9274                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9275                                    .border_l_1()
 9276                                    .border_color(cx.theme().colors().border)
 9277                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9278                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9279                                        el.child(
 9280                                            Label::new("Hold")
 9281                                                .size(LabelSize::Small)
 9282                                                .when(accept_keystroke.is_none(), |el| {
 9283                                                    el.strikethrough()
 9284                                                })
 9285                                                .line_height_style(LineHeightStyle::UiLabel),
 9286                                        )
 9287                                    })
 9288                                    .id("edit_prediction_cursor_popover_keybind")
 9289                                    .when(accept_keystroke.is_none(), |el| {
 9290                                        let status_colors = cx.theme().status();
 9291
 9292                                        el.bg(status_colors.error_background)
 9293                                            .border_color(status_colors.error.opacity(0.6))
 9294                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9295                                            .cursor_default()
 9296                                            .hoverable_tooltip(move |_window, cx| {
 9297                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9298                                                    .into()
 9299                                            })
 9300                                    })
 9301                                    .when_some(
 9302                                        accept_keystroke.as_ref(),
 9303                                        |el, accept_keystroke| {
 9304                                            el.child(h_flex().children(ui::render_modifiers(
 9305                                                accept_keystroke.modifiers(),
 9306                                                PlatformStyle::platform(),
 9307                                                Some(Color::Default),
 9308                                                Some(IconSize::XSmall.rems().into()),
 9309                                                false,
 9310                                            )))
 9311                                        },
 9312                                    ),
 9313                            )
 9314                            .into_any(),
 9315                    );
 9316                }
 9317
 9318                self.render_edit_prediction_cursor_popover_preview(
 9319                    prediction,
 9320                    cursor_point,
 9321                    style,
 9322                    cx,
 9323                )?
 9324            }
 9325
 9326            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9327                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9328                    stale_completion,
 9329                    cursor_point,
 9330                    style,
 9331                    cx,
 9332                )?,
 9333
 9334                None => pending_completion_container(provider_icon)
 9335                    .child(Label::new("...").size(LabelSize::Small)),
 9336            },
 9337
 9338            None => pending_completion_container(provider_icon)
 9339                .child(Label::new("...").size(LabelSize::Small)),
 9340        };
 9341
 9342        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9343            completion
 9344                .with_animation(
 9345                    "loading-completion",
 9346                    Animation::new(Duration::from_secs(2))
 9347                        .repeat()
 9348                        .with_easing(pulsating_between(0.4, 0.8)),
 9349                    |label, delta| label.opacity(delta),
 9350                )
 9351                .into_any_element()
 9352        } else {
 9353            completion.into_any_element()
 9354        };
 9355
 9356        let has_completion = self.active_edit_prediction.is_some();
 9357
 9358        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9359        Some(
 9360            h_flex()
 9361                .min_w(min_width)
 9362                .max_w(max_width)
 9363                .flex_1()
 9364                .elevation_2(cx)
 9365                .border_color(cx.theme().colors().border)
 9366                .child(
 9367                    div()
 9368                        .flex_1()
 9369                        .py_1()
 9370                        .px_2()
 9371                        .overflow_hidden()
 9372                        .child(completion),
 9373                )
 9374                .when_some(accept_keystroke, |el, accept_keystroke| {
 9375                    if !accept_keystroke.modifiers().modified() {
 9376                        return el;
 9377                    }
 9378
 9379                    el.child(
 9380                        h_flex()
 9381                            .h_full()
 9382                            .border_l_1()
 9383                            .rounded_r_lg()
 9384                            .border_color(cx.theme().colors().border)
 9385                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9386                            .gap_1()
 9387                            .py_1()
 9388                            .px_2()
 9389                            .child(
 9390                                h_flex()
 9391                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9392                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9393                                    .child(h_flex().children(ui::render_modifiers(
 9394                                        accept_keystroke.modifiers(),
 9395                                        PlatformStyle::platform(),
 9396                                        Some(if !has_completion {
 9397                                            Color::Muted
 9398                                        } else {
 9399                                            Color::Default
 9400                                        }),
 9401                                        None,
 9402                                        false,
 9403                                    ))),
 9404                            )
 9405                            .child(Label::new("Preview").into_any_element())
 9406                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9407                    )
 9408                })
 9409                .into_any(),
 9410        )
 9411    }
 9412
 9413    fn render_edit_prediction_cursor_popover_preview(
 9414        &self,
 9415        completion: &EditPredictionState,
 9416        cursor_point: Point,
 9417        style: &EditorStyle,
 9418        cx: &mut Context<Editor>,
 9419    ) -> Option<Div> {
 9420        use text::ToPoint as _;
 9421
 9422        fn render_relative_row_jump(
 9423            prefix: impl Into<String>,
 9424            current_row: u32,
 9425            target_row: u32,
 9426        ) -> Div {
 9427            let (row_diff, arrow) = if target_row < current_row {
 9428                (current_row - target_row, IconName::ArrowUp)
 9429            } else {
 9430                (target_row - current_row, IconName::ArrowDown)
 9431            };
 9432
 9433            h_flex()
 9434                .child(
 9435                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9436                        .color(Color::Muted)
 9437                        .size(LabelSize::Small),
 9438                )
 9439                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9440        }
 9441
 9442        let supports_jump = self
 9443            .edit_prediction_provider
 9444            .as_ref()
 9445            .map(|provider| provider.provider.supports_jump_to_edit())
 9446            .unwrap_or(true);
 9447
 9448        match &completion.completion {
 9449            EditPrediction::MoveWithin {
 9450                target, snapshot, ..
 9451            } => {
 9452                if !supports_jump {
 9453                    return None;
 9454                }
 9455
 9456                Some(
 9457                    h_flex()
 9458                        .px_2()
 9459                        .gap_2()
 9460                        .flex_1()
 9461                        .child(
 9462                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9463                                Icon::new(IconName::ZedPredictDown)
 9464                            } else {
 9465                                Icon::new(IconName::ZedPredictUp)
 9466                            },
 9467                        )
 9468                        .child(Label::new("Jump to Edit")),
 9469                )
 9470            }
 9471            EditPrediction::MoveOutside { snapshot, .. } => {
 9472                let file_name = snapshot
 9473                    .file()
 9474                    .map(|file| file.file_name(cx))
 9475                    .unwrap_or("untitled");
 9476                Some(
 9477                    h_flex()
 9478                        .px_2()
 9479                        .gap_2()
 9480                        .flex_1()
 9481                        .child(Icon::new(IconName::ZedPredict))
 9482                        .child(Label::new(format!("Jump to {file_name}"))),
 9483                )
 9484            }
 9485            EditPrediction::Edit {
 9486                edits,
 9487                edit_preview,
 9488                snapshot,
 9489                display_mode: _,
 9490            } => {
 9491                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9492
 9493                let (highlighted_edits, has_more_lines) =
 9494                    if let Some(edit_preview) = edit_preview.as_ref() {
 9495                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9496                            .first_line_preview()
 9497                    } else {
 9498                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9499                    };
 9500
 9501                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9502                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9503
 9504                let preview = h_flex()
 9505                    .gap_1()
 9506                    .min_w_16()
 9507                    .child(styled_text)
 9508                    .when(has_more_lines, |parent| parent.child(""));
 9509
 9510                let left = if supports_jump && first_edit_row != cursor_point.row {
 9511                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9512                        .into_any_element()
 9513                } else {
 9514                    let icon_name =
 9515                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9516                    Icon::new(icon_name).into_any_element()
 9517                };
 9518
 9519                Some(
 9520                    h_flex()
 9521                        .h_full()
 9522                        .flex_1()
 9523                        .gap_2()
 9524                        .pr_1()
 9525                        .overflow_x_hidden()
 9526                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9527                        .child(left)
 9528                        .child(preview),
 9529                )
 9530            }
 9531        }
 9532    }
 9533
 9534    pub fn render_context_menu(
 9535        &self,
 9536        style: &EditorStyle,
 9537        max_height_in_lines: u32,
 9538        window: &mut Window,
 9539        cx: &mut Context<Editor>,
 9540    ) -> Option<AnyElement> {
 9541        let menu = self.context_menu.borrow();
 9542        let menu = menu.as_ref()?;
 9543        if !menu.visible() {
 9544            return None;
 9545        };
 9546        Some(menu.render(style, max_height_in_lines, window, cx))
 9547    }
 9548
 9549    fn render_context_menu_aside(
 9550        &mut self,
 9551        max_size: Size<Pixels>,
 9552        window: &mut Window,
 9553        cx: &mut Context<Editor>,
 9554    ) -> Option<AnyElement> {
 9555        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9556            if menu.visible() {
 9557                menu.render_aside(max_size, window, cx)
 9558            } else {
 9559                None
 9560            }
 9561        })
 9562    }
 9563
 9564    fn hide_context_menu(
 9565        &mut self,
 9566        window: &mut Window,
 9567        cx: &mut Context<Self>,
 9568    ) -> Option<CodeContextMenu> {
 9569        cx.notify();
 9570        self.completion_tasks.clear();
 9571        let context_menu = self.context_menu.borrow_mut().take();
 9572        self.stale_edit_prediction_in_menu.take();
 9573        self.update_visible_edit_prediction(window, cx);
 9574        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9575            && let Some(completion_provider) = &self.completion_provider
 9576        {
 9577            completion_provider.selection_changed(None, window, cx);
 9578        }
 9579        context_menu
 9580    }
 9581
 9582    fn show_snippet_choices(
 9583        &mut self,
 9584        choices: &Vec<String>,
 9585        selection: Range<Anchor>,
 9586        cx: &mut Context<Self>,
 9587    ) {
 9588        let Some((_, buffer, _)) = self
 9589            .buffer()
 9590            .read(cx)
 9591            .excerpt_containing(selection.start, cx)
 9592        else {
 9593            return;
 9594        };
 9595        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9596        else {
 9597            return;
 9598        };
 9599        if buffer != end_buffer {
 9600            log::error!("expected anchor range to have matching buffer IDs");
 9601            return;
 9602        }
 9603
 9604        let id = post_inc(&mut self.next_completion_id);
 9605        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9606        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9607            CompletionsMenu::new_snippet_choices(
 9608                id,
 9609                true,
 9610                choices,
 9611                selection,
 9612                buffer,
 9613                snippet_sort_order,
 9614            ),
 9615        ));
 9616    }
 9617
 9618    pub fn insert_snippet(
 9619        &mut self,
 9620        insertion_ranges: &[Range<usize>],
 9621        snippet: Snippet,
 9622        window: &mut Window,
 9623        cx: &mut Context<Self>,
 9624    ) -> Result<()> {
 9625        struct Tabstop<T> {
 9626            is_end_tabstop: bool,
 9627            ranges: Vec<Range<T>>,
 9628            choices: Option<Vec<String>>,
 9629        }
 9630
 9631        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9632            let snippet_text: Arc<str> = snippet.text.clone().into();
 9633            let edits = insertion_ranges
 9634                .iter()
 9635                .cloned()
 9636                .map(|range| (range, snippet_text.clone()));
 9637            let autoindent_mode = AutoindentMode::Block {
 9638                original_indent_columns: Vec::new(),
 9639            };
 9640            buffer.edit(edits, Some(autoindent_mode), cx);
 9641
 9642            let snapshot = &*buffer.read(cx);
 9643            let snippet = &snippet;
 9644            snippet
 9645                .tabstops
 9646                .iter()
 9647                .map(|tabstop| {
 9648                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9649                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9650                    });
 9651                    let mut tabstop_ranges = tabstop
 9652                        .ranges
 9653                        .iter()
 9654                        .flat_map(|tabstop_range| {
 9655                            let mut delta = 0_isize;
 9656                            insertion_ranges.iter().map(move |insertion_range| {
 9657                                let insertion_start = insertion_range.start as isize + delta;
 9658                                delta +=
 9659                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9660
 9661                                let start = ((insertion_start + tabstop_range.start) as usize)
 9662                                    .min(snapshot.len());
 9663                                let end = ((insertion_start + tabstop_range.end) as usize)
 9664                                    .min(snapshot.len());
 9665                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9666                            })
 9667                        })
 9668                        .collect::<Vec<_>>();
 9669                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9670
 9671                    Tabstop {
 9672                        is_end_tabstop,
 9673                        ranges: tabstop_ranges,
 9674                        choices: tabstop.choices.clone(),
 9675                    }
 9676                })
 9677                .collect::<Vec<_>>()
 9678        });
 9679        if let Some(tabstop) = tabstops.first() {
 9680            self.change_selections(Default::default(), window, cx, |s| {
 9681                // Reverse order so that the first range is the newest created selection.
 9682                // Completions will use it and autoscroll will prioritize it.
 9683                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9684            });
 9685
 9686            if let Some(choices) = &tabstop.choices
 9687                && let Some(selection) = tabstop.ranges.first()
 9688            {
 9689                self.show_snippet_choices(choices, selection.clone(), cx)
 9690            }
 9691
 9692            // If we're already at the last tabstop and it's at the end of the snippet,
 9693            // we're done, we don't need to keep the state around.
 9694            if !tabstop.is_end_tabstop {
 9695                let choices = tabstops
 9696                    .iter()
 9697                    .map(|tabstop| tabstop.choices.clone())
 9698                    .collect();
 9699
 9700                let ranges = tabstops
 9701                    .into_iter()
 9702                    .map(|tabstop| tabstop.ranges)
 9703                    .collect::<Vec<_>>();
 9704
 9705                self.snippet_stack.push(SnippetState {
 9706                    active_index: 0,
 9707                    ranges,
 9708                    choices,
 9709                });
 9710            }
 9711
 9712            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9713            if self.autoclose_regions.is_empty() {
 9714                let snapshot = self.buffer.read(cx).snapshot(cx);
 9715                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9716                    let selection_head = selection.head();
 9717                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9718                        continue;
 9719                    };
 9720
 9721                    let mut bracket_pair = None;
 9722                    let max_lookup_length = scope
 9723                        .brackets()
 9724                        .map(|(pair, _)| {
 9725                            pair.start
 9726                                .as_str()
 9727                                .chars()
 9728                                .count()
 9729                                .max(pair.end.as_str().chars().count())
 9730                        })
 9731                        .max();
 9732                    if let Some(max_lookup_length) = max_lookup_length {
 9733                        let next_text = snapshot
 9734                            .chars_at(selection_head)
 9735                            .take(max_lookup_length)
 9736                            .collect::<String>();
 9737                        let prev_text = snapshot
 9738                            .reversed_chars_at(selection_head)
 9739                            .take(max_lookup_length)
 9740                            .collect::<String>();
 9741
 9742                        for (pair, enabled) in scope.brackets() {
 9743                            if enabled
 9744                                && pair.close
 9745                                && prev_text.starts_with(pair.start.as_str())
 9746                                && next_text.starts_with(pair.end.as_str())
 9747                            {
 9748                                bracket_pair = Some(pair.clone());
 9749                                break;
 9750                            }
 9751                        }
 9752                    }
 9753
 9754                    if let Some(pair) = bracket_pair {
 9755                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9756                        let autoclose_enabled =
 9757                            self.use_autoclose && snapshot_settings.use_autoclose;
 9758                        if autoclose_enabled {
 9759                            let start = snapshot.anchor_after(selection_head);
 9760                            let end = snapshot.anchor_after(selection_head);
 9761                            self.autoclose_regions.push(AutocloseRegion {
 9762                                selection_id: selection.id,
 9763                                range: start..end,
 9764                                pair,
 9765                            });
 9766                        }
 9767                    }
 9768                }
 9769            }
 9770        }
 9771        Ok(())
 9772    }
 9773
 9774    pub fn move_to_next_snippet_tabstop(
 9775        &mut self,
 9776        window: &mut Window,
 9777        cx: &mut Context<Self>,
 9778    ) -> bool {
 9779        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9780    }
 9781
 9782    pub fn move_to_prev_snippet_tabstop(
 9783        &mut self,
 9784        window: &mut Window,
 9785        cx: &mut Context<Self>,
 9786    ) -> bool {
 9787        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9788    }
 9789
 9790    pub fn move_to_snippet_tabstop(
 9791        &mut self,
 9792        bias: Bias,
 9793        window: &mut Window,
 9794        cx: &mut Context<Self>,
 9795    ) -> bool {
 9796        if let Some(mut snippet) = self.snippet_stack.pop() {
 9797            match bias {
 9798                Bias::Left => {
 9799                    if snippet.active_index > 0 {
 9800                        snippet.active_index -= 1;
 9801                    } else {
 9802                        self.snippet_stack.push(snippet);
 9803                        return false;
 9804                    }
 9805                }
 9806                Bias::Right => {
 9807                    if snippet.active_index + 1 < snippet.ranges.len() {
 9808                        snippet.active_index += 1;
 9809                    } else {
 9810                        self.snippet_stack.push(snippet);
 9811                        return false;
 9812                    }
 9813                }
 9814            }
 9815            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9816                self.change_selections(Default::default(), window, cx, |s| {
 9817                    // Reverse order so that the first range is the newest created selection.
 9818                    // Completions will use it and autoscroll will prioritize it.
 9819                    s.select_ranges(current_ranges.iter().rev().cloned())
 9820                });
 9821
 9822                if let Some(choices) = &snippet.choices[snippet.active_index]
 9823                    && let Some(selection) = current_ranges.first()
 9824                {
 9825                    self.show_snippet_choices(choices, selection.clone(), cx);
 9826                }
 9827
 9828                // If snippet state is not at the last tabstop, push it back on the stack
 9829                if snippet.active_index + 1 < snippet.ranges.len() {
 9830                    self.snippet_stack.push(snippet);
 9831                }
 9832                return true;
 9833            }
 9834        }
 9835
 9836        false
 9837    }
 9838
 9839    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9840        self.transact(window, cx, |this, window, cx| {
 9841            this.select_all(&SelectAll, window, cx);
 9842            this.insert("", window, cx);
 9843        });
 9844    }
 9845
 9846    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9847        if self.read_only(cx) {
 9848            return;
 9849        }
 9850        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9851        self.transact(window, cx, |this, window, cx| {
 9852            this.select_autoclose_pair(window, cx);
 9853
 9854            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9855
 9856            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9857            if !this.linked_edit_ranges.is_empty() {
 9858                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9859                let snapshot = this.buffer.read(cx).snapshot(cx);
 9860
 9861                for selection in selections.iter() {
 9862                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9863                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9864                    if selection_start.buffer_id != selection_end.buffer_id {
 9865                        continue;
 9866                    }
 9867                    if let Some(ranges) =
 9868                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9869                    {
 9870                        for (buffer, entries) in ranges {
 9871                            linked_ranges.entry(buffer).or_default().extend(entries);
 9872                        }
 9873                    }
 9874                }
 9875            }
 9876
 9877            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9878            for selection in &mut selections {
 9879                if selection.is_empty() {
 9880                    let old_head = selection.head();
 9881                    let mut new_head =
 9882                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9883                            .to_point(&display_map);
 9884                    if let Some((buffer, line_buffer_range)) = display_map
 9885                        .buffer_snapshot()
 9886                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9887                    {
 9888                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9889                        let indent_len = match indent_size.kind {
 9890                            IndentKind::Space => {
 9891                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9892                            }
 9893                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9894                        };
 9895                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9896                            let indent_len = indent_len.get();
 9897                            new_head = cmp::min(
 9898                                new_head,
 9899                                MultiBufferPoint::new(
 9900                                    old_head.row,
 9901                                    ((old_head.column - 1) / indent_len) * indent_len,
 9902                                ),
 9903                            );
 9904                        }
 9905                    }
 9906
 9907                    selection.set_head(new_head, SelectionGoal::None);
 9908                }
 9909            }
 9910
 9911            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9912            this.insert("", window, cx);
 9913            let empty_str: Arc<str> = Arc::from("");
 9914            for (buffer, edits) in linked_ranges {
 9915                let snapshot = buffer.read(cx).snapshot();
 9916                use text::ToPoint as TP;
 9917
 9918                let edits = edits
 9919                    .into_iter()
 9920                    .map(|range| {
 9921                        let end_point = TP::to_point(&range.end, &snapshot);
 9922                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9923
 9924                        if end_point == start_point {
 9925                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9926                                .saturating_sub(1);
 9927                            start_point =
 9928                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9929                        };
 9930
 9931                        (start_point..end_point, empty_str.clone())
 9932                    })
 9933                    .sorted_by_key(|(range, _)| range.start)
 9934                    .collect::<Vec<_>>();
 9935                buffer.update(cx, |this, cx| {
 9936                    this.edit(edits, None, cx);
 9937                })
 9938            }
 9939            this.refresh_edit_prediction(true, false, window, cx);
 9940            refresh_linked_ranges(this, window, cx);
 9941        });
 9942    }
 9943
 9944    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9945        if self.read_only(cx) {
 9946            return;
 9947        }
 9948        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9949        self.transact(window, cx, |this, window, cx| {
 9950            this.change_selections(Default::default(), window, cx, |s| {
 9951                s.move_with(|map, selection| {
 9952                    if selection.is_empty() {
 9953                        let cursor = movement::right(map, selection.head());
 9954                        selection.end = cursor;
 9955                        selection.reversed = true;
 9956                        selection.goal = SelectionGoal::None;
 9957                    }
 9958                })
 9959            });
 9960            this.insert("", window, cx);
 9961            this.refresh_edit_prediction(true, false, window, cx);
 9962        });
 9963    }
 9964
 9965    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9966        if self.mode.is_single_line() {
 9967            cx.propagate();
 9968            return;
 9969        }
 9970
 9971        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9972        if self.move_to_prev_snippet_tabstop(window, cx) {
 9973            return;
 9974        }
 9975        self.outdent(&Outdent, window, cx);
 9976    }
 9977
 9978    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9979        if self.mode.is_single_line() {
 9980            cx.propagate();
 9981            return;
 9982        }
 9983
 9984        if self.move_to_next_snippet_tabstop(window, cx) {
 9985            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9986            return;
 9987        }
 9988        if self.read_only(cx) {
 9989            return;
 9990        }
 9991        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9992        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 9993        let buffer = self.buffer.read(cx);
 9994        let snapshot = buffer.snapshot(cx);
 9995        let rows_iter = selections.iter().map(|s| s.head().row);
 9996        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9997
 9998        let has_some_cursor_in_whitespace = selections
 9999            .iter()
10000            .filter(|selection| selection.is_empty())
10001            .any(|selection| {
10002                let cursor = selection.head();
10003                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10004                cursor.column < current_indent.len
10005            });
10006
10007        let mut edits = Vec::new();
10008        let mut prev_edited_row = 0;
10009        let mut row_delta = 0;
10010        for selection in &mut selections {
10011            if selection.start.row != prev_edited_row {
10012                row_delta = 0;
10013            }
10014            prev_edited_row = selection.end.row;
10015
10016            // If the selection is non-empty, then increase the indentation of the selected lines.
10017            if !selection.is_empty() {
10018                row_delta =
10019                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10020                continue;
10021            }
10022
10023            let cursor = selection.head();
10024            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10025            if let Some(suggested_indent) =
10026                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10027            {
10028                // Don't do anything if already at suggested indent
10029                // and there is any other cursor which is not
10030                if has_some_cursor_in_whitespace
10031                    && cursor.column == current_indent.len
10032                    && current_indent.len == suggested_indent.len
10033                {
10034                    continue;
10035                }
10036
10037                // Adjust line and move cursor to suggested indent
10038                // if cursor is not at suggested indent
10039                if cursor.column < suggested_indent.len
10040                    && cursor.column <= current_indent.len
10041                    && current_indent.len <= suggested_indent.len
10042                {
10043                    selection.start = Point::new(cursor.row, suggested_indent.len);
10044                    selection.end = selection.start;
10045                    if row_delta == 0 {
10046                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10047                            cursor.row,
10048                            current_indent,
10049                            suggested_indent,
10050                        ));
10051                        row_delta = suggested_indent.len - current_indent.len;
10052                    }
10053                    continue;
10054                }
10055
10056                // If current indent is more than suggested indent
10057                // only move cursor to current indent and skip indent
10058                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10059                    selection.start = Point::new(cursor.row, current_indent.len);
10060                    selection.end = selection.start;
10061                    continue;
10062                }
10063            }
10064
10065            // Otherwise, insert a hard or soft tab.
10066            let settings = buffer.language_settings_at(cursor, cx);
10067            let tab_size = if settings.hard_tabs {
10068                IndentSize::tab()
10069            } else {
10070                let tab_size = settings.tab_size.get();
10071                let indent_remainder = snapshot
10072                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10073                    .flat_map(str::chars)
10074                    .fold(row_delta % tab_size, |counter: u32, c| {
10075                        if c == '\t' {
10076                            0
10077                        } else {
10078                            (counter + 1) % tab_size
10079                        }
10080                    });
10081
10082                let chars_to_next_tab_stop = tab_size - indent_remainder;
10083                IndentSize::spaces(chars_to_next_tab_stop)
10084            };
10085            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10086            selection.end = selection.start;
10087            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10088            row_delta += tab_size.len;
10089        }
10090
10091        self.transact(window, cx, |this, window, cx| {
10092            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10093            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10094            this.refresh_edit_prediction(true, false, window, cx);
10095        });
10096    }
10097
10098    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10099        if self.read_only(cx) {
10100            return;
10101        }
10102        if self.mode.is_single_line() {
10103            cx.propagate();
10104            return;
10105        }
10106
10107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10108        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10109        let mut prev_edited_row = 0;
10110        let mut row_delta = 0;
10111        let mut edits = Vec::new();
10112        let buffer = self.buffer.read(cx);
10113        let snapshot = buffer.snapshot(cx);
10114        for selection in &mut selections {
10115            if selection.start.row != prev_edited_row {
10116                row_delta = 0;
10117            }
10118            prev_edited_row = selection.end.row;
10119
10120            row_delta =
10121                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10122        }
10123
10124        self.transact(window, cx, |this, window, cx| {
10125            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10126            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10127        });
10128    }
10129
10130    fn indent_selection(
10131        buffer: &MultiBuffer,
10132        snapshot: &MultiBufferSnapshot,
10133        selection: &mut Selection<Point>,
10134        edits: &mut Vec<(Range<Point>, String)>,
10135        delta_for_start_row: u32,
10136        cx: &App,
10137    ) -> u32 {
10138        let settings = buffer.language_settings_at(selection.start, cx);
10139        let tab_size = settings.tab_size.get();
10140        let indent_kind = if settings.hard_tabs {
10141            IndentKind::Tab
10142        } else {
10143            IndentKind::Space
10144        };
10145        let mut start_row = selection.start.row;
10146        let mut end_row = selection.end.row + 1;
10147
10148        // If a selection ends at the beginning of a line, don't indent
10149        // that last line.
10150        if selection.end.column == 0 && selection.end.row > selection.start.row {
10151            end_row -= 1;
10152        }
10153
10154        // Avoid re-indenting a row that has already been indented by a
10155        // previous selection, but still update this selection's column
10156        // to reflect that indentation.
10157        if delta_for_start_row > 0 {
10158            start_row += 1;
10159            selection.start.column += delta_for_start_row;
10160            if selection.end.row == selection.start.row {
10161                selection.end.column += delta_for_start_row;
10162            }
10163        }
10164
10165        let mut delta_for_end_row = 0;
10166        let has_multiple_rows = start_row + 1 != end_row;
10167        for row in start_row..end_row {
10168            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10169            let indent_delta = match (current_indent.kind, indent_kind) {
10170                (IndentKind::Space, IndentKind::Space) => {
10171                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10172                    IndentSize::spaces(columns_to_next_tab_stop)
10173                }
10174                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10175                (_, IndentKind::Tab) => IndentSize::tab(),
10176            };
10177
10178            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10179                0
10180            } else {
10181                selection.start.column
10182            };
10183            let row_start = Point::new(row, start);
10184            edits.push((
10185                row_start..row_start,
10186                indent_delta.chars().collect::<String>(),
10187            ));
10188
10189            // Update this selection's endpoints to reflect the indentation.
10190            if row == selection.start.row {
10191                selection.start.column += indent_delta.len;
10192            }
10193            if row == selection.end.row {
10194                selection.end.column += indent_delta.len;
10195                delta_for_end_row = indent_delta.len;
10196            }
10197        }
10198
10199        if selection.start.row == selection.end.row {
10200            delta_for_start_row + delta_for_end_row
10201        } else {
10202            delta_for_end_row
10203        }
10204    }
10205
10206    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10207        if self.read_only(cx) {
10208            return;
10209        }
10210        if self.mode.is_single_line() {
10211            cx.propagate();
10212            return;
10213        }
10214
10215        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10216        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10217        let selections = self.selections.all::<Point>(&display_map);
10218        let mut deletion_ranges = Vec::new();
10219        let mut last_outdent = None;
10220        {
10221            let buffer = self.buffer.read(cx);
10222            let snapshot = buffer.snapshot(cx);
10223            for selection in &selections {
10224                let settings = buffer.language_settings_at(selection.start, cx);
10225                let tab_size = settings.tab_size.get();
10226                let mut rows = selection.spanned_rows(false, &display_map);
10227
10228                // Avoid re-outdenting a row that has already been outdented by a
10229                // previous selection.
10230                if let Some(last_row) = last_outdent
10231                    && last_row == rows.start
10232                {
10233                    rows.start = rows.start.next_row();
10234                }
10235                let has_multiple_rows = rows.len() > 1;
10236                for row in rows.iter_rows() {
10237                    let indent_size = snapshot.indent_size_for_line(row);
10238                    if indent_size.len > 0 {
10239                        let deletion_len = match indent_size.kind {
10240                            IndentKind::Space => {
10241                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10242                                if columns_to_prev_tab_stop == 0 {
10243                                    tab_size
10244                                } else {
10245                                    columns_to_prev_tab_stop
10246                                }
10247                            }
10248                            IndentKind::Tab => 1,
10249                        };
10250                        let start = if has_multiple_rows
10251                            || deletion_len > selection.start.column
10252                            || indent_size.len < selection.start.column
10253                        {
10254                            0
10255                        } else {
10256                            selection.start.column - deletion_len
10257                        };
10258                        deletion_ranges.push(
10259                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10260                        );
10261                        last_outdent = Some(row);
10262                    }
10263                }
10264            }
10265        }
10266
10267        self.transact(window, cx, |this, window, cx| {
10268            this.buffer.update(cx, |buffer, cx| {
10269                let empty_str: Arc<str> = Arc::default();
10270                buffer.edit(
10271                    deletion_ranges
10272                        .into_iter()
10273                        .map(|range| (range, empty_str.clone())),
10274                    None,
10275                    cx,
10276                );
10277            });
10278            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10279            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10280        });
10281    }
10282
10283    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10284        if self.read_only(cx) {
10285            return;
10286        }
10287        if self.mode.is_single_line() {
10288            cx.propagate();
10289            return;
10290        }
10291
10292        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10293        let selections = self
10294            .selections
10295            .all::<usize>(&self.display_snapshot(cx))
10296            .into_iter()
10297            .map(|s| s.range());
10298
10299        self.transact(window, cx, |this, window, cx| {
10300            this.buffer.update(cx, |buffer, cx| {
10301                buffer.autoindent_ranges(selections, cx);
10302            });
10303            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10304            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10305        });
10306    }
10307
10308    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10310        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10311        let selections = self.selections.all::<Point>(&display_map);
10312
10313        let mut new_cursors = Vec::new();
10314        let mut edit_ranges = Vec::new();
10315        let mut selections = selections.iter().peekable();
10316        while let Some(selection) = selections.next() {
10317            let mut rows = selection.spanned_rows(false, &display_map);
10318
10319            // Accumulate contiguous regions of rows that we want to delete.
10320            while let Some(next_selection) = selections.peek() {
10321                let next_rows = next_selection.spanned_rows(false, &display_map);
10322                if next_rows.start <= rows.end {
10323                    rows.end = next_rows.end;
10324                    selections.next().unwrap();
10325                } else {
10326                    break;
10327                }
10328            }
10329
10330            let buffer = display_map.buffer_snapshot();
10331            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10332            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10333                // If there's a line after the range, delete the \n from the end of the row range
10334                (
10335                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10336                    rows.end,
10337                )
10338            } else {
10339                // If there isn't a line after the range, delete the \n from the line before the
10340                // start of the row range
10341                edit_start = edit_start.saturating_sub(1);
10342                (buffer.len(), rows.start.previous_row())
10343            };
10344
10345            let text_layout_details = self.text_layout_details(window);
10346            let x = display_map.x_for_display_point(
10347                selection.head().to_display_point(&display_map),
10348                &text_layout_details,
10349            );
10350            let row = Point::new(target_row.0, 0)
10351                .to_display_point(&display_map)
10352                .row();
10353            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10354
10355            new_cursors.push((
10356                selection.id,
10357                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10358                SelectionGoal::None,
10359            ));
10360            edit_ranges.push(edit_start..edit_end);
10361        }
10362
10363        self.transact(window, cx, |this, window, cx| {
10364            let buffer = this.buffer.update(cx, |buffer, cx| {
10365                let empty_str: Arc<str> = Arc::default();
10366                buffer.edit(
10367                    edit_ranges
10368                        .into_iter()
10369                        .map(|range| (range, empty_str.clone())),
10370                    None,
10371                    cx,
10372                );
10373                buffer.snapshot(cx)
10374            });
10375            let new_selections = new_cursors
10376                .into_iter()
10377                .map(|(id, cursor, goal)| {
10378                    let cursor = cursor.to_point(&buffer);
10379                    Selection {
10380                        id,
10381                        start: cursor,
10382                        end: cursor,
10383                        reversed: false,
10384                        goal,
10385                    }
10386                })
10387                .collect();
10388
10389            this.change_selections(Default::default(), window, cx, |s| {
10390                s.select(new_selections);
10391            });
10392        });
10393    }
10394
10395    pub fn join_lines_impl(
10396        &mut self,
10397        insert_whitespace: bool,
10398        window: &mut Window,
10399        cx: &mut Context<Self>,
10400    ) {
10401        if self.read_only(cx) {
10402            return;
10403        }
10404        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10405        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10406            let start = MultiBufferRow(selection.start.row);
10407            // Treat single line selections as if they include the next line. Otherwise this action
10408            // would do nothing for single line selections individual cursors.
10409            let end = if selection.start.row == selection.end.row {
10410                MultiBufferRow(selection.start.row + 1)
10411            } else {
10412                MultiBufferRow(selection.end.row)
10413            };
10414
10415            if let Some(last_row_range) = row_ranges.last_mut()
10416                && start <= last_row_range.end
10417            {
10418                last_row_range.end = end;
10419                continue;
10420            }
10421            row_ranges.push(start..end);
10422        }
10423
10424        let snapshot = self.buffer.read(cx).snapshot(cx);
10425        let mut cursor_positions = Vec::new();
10426        for row_range in &row_ranges {
10427            let anchor = snapshot.anchor_before(Point::new(
10428                row_range.end.previous_row().0,
10429                snapshot.line_len(row_range.end.previous_row()),
10430            ));
10431            cursor_positions.push(anchor..anchor);
10432        }
10433
10434        self.transact(window, cx, |this, window, cx| {
10435            for row_range in row_ranges.into_iter().rev() {
10436                for row in row_range.iter_rows().rev() {
10437                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10438                    let next_line_row = row.next_row();
10439                    let indent = snapshot.indent_size_for_line(next_line_row);
10440                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10441
10442                    let replace =
10443                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10444                            " "
10445                        } else {
10446                            ""
10447                        };
10448
10449                    this.buffer.update(cx, |buffer, cx| {
10450                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10451                    });
10452                }
10453            }
10454
10455            this.change_selections(Default::default(), window, cx, |s| {
10456                s.select_anchor_ranges(cursor_positions)
10457            });
10458        });
10459    }
10460
10461    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10462        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10463        self.join_lines_impl(true, window, cx);
10464    }
10465
10466    pub fn sort_lines_case_sensitive(
10467        &mut self,
10468        _: &SortLinesCaseSensitive,
10469        window: &mut Window,
10470        cx: &mut Context<Self>,
10471    ) {
10472        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10473    }
10474
10475    pub fn sort_lines_by_length(
10476        &mut self,
10477        _: &SortLinesByLength,
10478        window: &mut Window,
10479        cx: &mut Context<Self>,
10480    ) {
10481        self.manipulate_immutable_lines(window, cx, |lines| {
10482            lines.sort_by_key(|&line| line.chars().count())
10483        })
10484    }
10485
10486    pub fn sort_lines_case_insensitive(
10487        &mut self,
10488        _: &SortLinesCaseInsensitive,
10489        window: &mut Window,
10490        cx: &mut Context<Self>,
10491    ) {
10492        self.manipulate_immutable_lines(window, cx, |lines| {
10493            lines.sort_by_key(|line| line.to_lowercase())
10494        })
10495    }
10496
10497    pub fn unique_lines_case_insensitive(
10498        &mut self,
10499        _: &UniqueLinesCaseInsensitive,
10500        window: &mut Window,
10501        cx: &mut Context<Self>,
10502    ) {
10503        self.manipulate_immutable_lines(window, cx, |lines| {
10504            let mut seen = HashSet::default();
10505            lines.retain(|line| seen.insert(line.to_lowercase()));
10506        })
10507    }
10508
10509    pub fn unique_lines_case_sensitive(
10510        &mut self,
10511        _: &UniqueLinesCaseSensitive,
10512        window: &mut Window,
10513        cx: &mut Context<Self>,
10514    ) {
10515        self.manipulate_immutable_lines(window, cx, |lines| {
10516            let mut seen = HashSet::default();
10517            lines.retain(|line| seen.insert(*line));
10518        })
10519    }
10520
10521    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10522        let snapshot = self.buffer.read(cx).snapshot(cx);
10523        for selection in self.selections.disjoint_anchors_arc().iter() {
10524            if snapshot
10525                .language_at(selection.start)
10526                .and_then(|lang| lang.config().wrap_characters.as_ref())
10527                .is_some()
10528            {
10529                return true;
10530            }
10531        }
10532        false
10533    }
10534
10535    fn wrap_selections_in_tag(
10536        &mut self,
10537        _: &WrapSelectionsInTag,
10538        window: &mut Window,
10539        cx: &mut Context<Self>,
10540    ) {
10541        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10542
10543        let snapshot = self.buffer.read(cx).snapshot(cx);
10544
10545        let mut edits = Vec::new();
10546        let mut boundaries = Vec::new();
10547
10548        for selection in self
10549            .selections
10550            .all_adjusted(&self.display_snapshot(cx))
10551            .iter()
10552        {
10553            let Some(wrap_config) = snapshot
10554                .language_at(selection.start)
10555                .and_then(|lang| lang.config().wrap_characters.clone())
10556            else {
10557                continue;
10558            };
10559
10560            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10561            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10562
10563            let start_before = snapshot.anchor_before(selection.start);
10564            let end_after = snapshot.anchor_after(selection.end);
10565
10566            edits.push((start_before..start_before, open_tag));
10567            edits.push((end_after..end_after, close_tag));
10568
10569            boundaries.push((
10570                start_before,
10571                end_after,
10572                wrap_config.start_prefix.len(),
10573                wrap_config.end_suffix.len(),
10574            ));
10575        }
10576
10577        if edits.is_empty() {
10578            return;
10579        }
10580
10581        self.transact(window, cx, |this, window, cx| {
10582            let buffer = this.buffer.update(cx, |buffer, cx| {
10583                buffer.edit(edits, None, cx);
10584                buffer.snapshot(cx)
10585            });
10586
10587            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10588            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10589                boundaries.into_iter()
10590            {
10591                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10592                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10593                new_selections.push(open_offset..open_offset);
10594                new_selections.push(close_offset..close_offset);
10595            }
10596
10597            this.change_selections(Default::default(), window, cx, |s| {
10598                s.select_ranges(new_selections);
10599            });
10600
10601            this.request_autoscroll(Autoscroll::fit(), cx);
10602        });
10603    }
10604
10605    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10606        let Some(project) = self.project.clone() else {
10607            return;
10608        };
10609        self.reload(project, window, cx)
10610            .detach_and_notify_err(window, cx);
10611    }
10612
10613    pub fn restore_file(
10614        &mut self,
10615        _: &::git::RestoreFile,
10616        window: &mut Window,
10617        cx: &mut Context<Self>,
10618    ) {
10619        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10620        let mut buffer_ids = HashSet::default();
10621        let snapshot = self.buffer().read(cx).snapshot(cx);
10622        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10623            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10624        }
10625
10626        let buffer = self.buffer().read(cx);
10627        let ranges = buffer_ids
10628            .into_iter()
10629            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10630            .collect::<Vec<_>>();
10631
10632        self.restore_hunks_in_ranges(ranges, window, cx);
10633    }
10634
10635    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10636        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10637        let selections = self
10638            .selections
10639            .all(&self.display_snapshot(cx))
10640            .into_iter()
10641            .map(|s| s.range())
10642            .collect();
10643        self.restore_hunks_in_ranges(selections, window, cx);
10644    }
10645
10646    pub fn restore_hunks_in_ranges(
10647        &mut self,
10648        ranges: Vec<Range<Point>>,
10649        window: &mut Window,
10650        cx: &mut Context<Editor>,
10651    ) {
10652        let mut revert_changes = HashMap::default();
10653        let chunk_by = self
10654            .snapshot(window, cx)
10655            .hunks_for_ranges(ranges)
10656            .into_iter()
10657            .chunk_by(|hunk| hunk.buffer_id);
10658        for (buffer_id, hunks) in &chunk_by {
10659            let hunks = hunks.collect::<Vec<_>>();
10660            for hunk in &hunks {
10661                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10662            }
10663            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10664        }
10665        drop(chunk_by);
10666        if !revert_changes.is_empty() {
10667            self.transact(window, cx, |editor, window, cx| {
10668                editor.restore(revert_changes, window, cx);
10669            });
10670        }
10671    }
10672
10673    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10674        if let Some(status) = self
10675            .addons
10676            .iter()
10677            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10678        {
10679            return Some(status);
10680        }
10681        self.project
10682            .as_ref()?
10683            .read(cx)
10684            .status_for_buffer_id(buffer_id, cx)
10685    }
10686
10687    pub fn open_active_item_in_terminal(
10688        &mut self,
10689        _: &OpenInTerminal,
10690        window: &mut Window,
10691        cx: &mut Context<Self>,
10692    ) {
10693        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10694            let project_path = buffer.read(cx).project_path(cx)?;
10695            let project = self.project()?.read(cx);
10696            let entry = project.entry_for_path(&project_path, cx)?;
10697            let parent = match &entry.canonical_path {
10698                Some(canonical_path) => canonical_path.to_path_buf(),
10699                None => project.absolute_path(&project_path, cx)?,
10700            }
10701            .parent()?
10702            .to_path_buf();
10703            Some(parent)
10704        }) {
10705            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10706        }
10707    }
10708
10709    fn set_breakpoint_context_menu(
10710        &mut self,
10711        display_row: DisplayRow,
10712        position: Option<Anchor>,
10713        clicked_point: gpui::Point<Pixels>,
10714        window: &mut Window,
10715        cx: &mut Context<Self>,
10716    ) {
10717        let source = self
10718            .buffer
10719            .read(cx)
10720            .snapshot(cx)
10721            .anchor_before(Point::new(display_row.0, 0u32));
10722
10723        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10724
10725        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10726            self,
10727            source,
10728            clicked_point,
10729            context_menu,
10730            window,
10731            cx,
10732        );
10733    }
10734
10735    fn add_edit_breakpoint_block(
10736        &mut self,
10737        anchor: Anchor,
10738        breakpoint: &Breakpoint,
10739        edit_action: BreakpointPromptEditAction,
10740        window: &mut Window,
10741        cx: &mut Context<Self>,
10742    ) {
10743        let weak_editor = cx.weak_entity();
10744        let bp_prompt = cx.new(|cx| {
10745            BreakpointPromptEditor::new(
10746                weak_editor,
10747                anchor,
10748                breakpoint.clone(),
10749                edit_action,
10750                window,
10751                cx,
10752            )
10753        });
10754
10755        let height = bp_prompt.update(cx, |this, cx| {
10756            this.prompt
10757                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10758        });
10759        let cloned_prompt = bp_prompt.clone();
10760        let blocks = vec![BlockProperties {
10761            style: BlockStyle::Sticky,
10762            placement: BlockPlacement::Above(anchor),
10763            height: Some(height),
10764            render: Arc::new(move |cx| {
10765                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10766                cloned_prompt.clone().into_any_element()
10767            }),
10768            priority: 0,
10769        }];
10770
10771        let focus_handle = bp_prompt.focus_handle(cx);
10772        window.focus(&focus_handle);
10773
10774        let block_ids = self.insert_blocks(blocks, None, cx);
10775        bp_prompt.update(cx, |prompt, _| {
10776            prompt.add_block_ids(block_ids);
10777        });
10778    }
10779
10780    pub(crate) fn breakpoint_at_row(
10781        &self,
10782        row: u32,
10783        window: &mut Window,
10784        cx: &mut Context<Self>,
10785    ) -> Option<(Anchor, Breakpoint)> {
10786        let snapshot = self.snapshot(window, cx);
10787        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10788
10789        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10790    }
10791
10792    pub(crate) fn breakpoint_at_anchor(
10793        &self,
10794        breakpoint_position: Anchor,
10795        snapshot: &EditorSnapshot,
10796        cx: &mut Context<Self>,
10797    ) -> Option<(Anchor, Breakpoint)> {
10798        let buffer = self
10799            .buffer
10800            .read(cx)
10801            .buffer_for_anchor(breakpoint_position, cx)?;
10802
10803        let enclosing_excerpt = breakpoint_position.excerpt_id;
10804        let buffer_snapshot = buffer.read(cx).snapshot();
10805
10806        let row = buffer_snapshot
10807            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10808            .row;
10809
10810        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10811        let anchor_end = snapshot
10812            .buffer_snapshot()
10813            .anchor_after(Point::new(row, line_len));
10814
10815        self.breakpoint_store
10816            .as_ref()?
10817            .read_with(cx, |breakpoint_store, cx| {
10818                breakpoint_store
10819                    .breakpoints(
10820                        &buffer,
10821                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10822                        &buffer_snapshot,
10823                        cx,
10824                    )
10825                    .next()
10826                    .and_then(|(bp, _)| {
10827                        let breakpoint_row = buffer_snapshot
10828                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10829                            .row;
10830
10831                        if breakpoint_row == row {
10832                            snapshot
10833                                .buffer_snapshot()
10834                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10835                                .map(|position| (position, bp.bp.clone()))
10836                        } else {
10837                            None
10838                        }
10839                    })
10840            })
10841    }
10842
10843    pub fn edit_log_breakpoint(
10844        &mut self,
10845        _: &EditLogBreakpoint,
10846        window: &mut Window,
10847        cx: &mut Context<Self>,
10848    ) {
10849        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10850            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10851                message: None,
10852                state: BreakpointState::Enabled,
10853                condition: None,
10854                hit_condition: None,
10855            });
10856
10857            self.add_edit_breakpoint_block(
10858                anchor,
10859                &breakpoint,
10860                BreakpointPromptEditAction::Log,
10861                window,
10862                cx,
10863            );
10864        }
10865    }
10866
10867    fn breakpoints_at_cursors(
10868        &self,
10869        window: &mut Window,
10870        cx: &mut Context<Self>,
10871    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10872        let snapshot = self.snapshot(window, cx);
10873        let cursors = self
10874            .selections
10875            .disjoint_anchors_arc()
10876            .iter()
10877            .map(|selection| {
10878                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10879
10880                let breakpoint_position = self
10881                    .breakpoint_at_row(cursor_position.row, window, cx)
10882                    .map(|bp| bp.0)
10883                    .unwrap_or_else(|| {
10884                        snapshot
10885                            .display_snapshot
10886                            .buffer_snapshot()
10887                            .anchor_after(Point::new(cursor_position.row, 0))
10888                    });
10889
10890                let breakpoint = self
10891                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10892                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10893
10894                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10895            })
10896            // 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.
10897            .collect::<HashMap<Anchor, _>>();
10898
10899        cursors.into_iter().collect()
10900    }
10901
10902    pub fn enable_breakpoint(
10903        &mut self,
10904        _: &crate::actions::EnableBreakpoint,
10905        window: &mut Window,
10906        cx: &mut Context<Self>,
10907    ) {
10908        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10909            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10910                continue;
10911            };
10912            self.edit_breakpoint_at_anchor(
10913                anchor,
10914                breakpoint,
10915                BreakpointEditAction::InvertState,
10916                cx,
10917            );
10918        }
10919    }
10920
10921    pub fn disable_breakpoint(
10922        &mut self,
10923        _: &crate::actions::DisableBreakpoint,
10924        window: &mut Window,
10925        cx: &mut Context<Self>,
10926    ) {
10927        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10928            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10929                continue;
10930            };
10931            self.edit_breakpoint_at_anchor(
10932                anchor,
10933                breakpoint,
10934                BreakpointEditAction::InvertState,
10935                cx,
10936            );
10937        }
10938    }
10939
10940    pub fn toggle_breakpoint(
10941        &mut self,
10942        _: &crate::actions::ToggleBreakpoint,
10943        window: &mut Window,
10944        cx: &mut Context<Self>,
10945    ) {
10946        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10947            if let Some(breakpoint) = breakpoint {
10948                self.edit_breakpoint_at_anchor(
10949                    anchor,
10950                    breakpoint,
10951                    BreakpointEditAction::Toggle,
10952                    cx,
10953                );
10954            } else {
10955                self.edit_breakpoint_at_anchor(
10956                    anchor,
10957                    Breakpoint::new_standard(),
10958                    BreakpointEditAction::Toggle,
10959                    cx,
10960                );
10961            }
10962        }
10963    }
10964
10965    pub fn edit_breakpoint_at_anchor(
10966        &mut self,
10967        breakpoint_position: Anchor,
10968        breakpoint: Breakpoint,
10969        edit_action: BreakpointEditAction,
10970        cx: &mut Context<Self>,
10971    ) {
10972        let Some(breakpoint_store) = &self.breakpoint_store else {
10973            return;
10974        };
10975
10976        let Some(buffer) = self
10977            .buffer
10978            .read(cx)
10979            .buffer_for_anchor(breakpoint_position, cx)
10980        else {
10981            return;
10982        };
10983
10984        breakpoint_store.update(cx, |breakpoint_store, cx| {
10985            breakpoint_store.toggle_breakpoint(
10986                buffer,
10987                BreakpointWithPosition {
10988                    position: breakpoint_position.text_anchor,
10989                    bp: breakpoint,
10990                },
10991                edit_action,
10992                cx,
10993            );
10994        });
10995
10996        cx.notify();
10997    }
10998
10999    #[cfg(any(test, feature = "test-support"))]
11000    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11001        self.breakpoint_store.clone()
11002    }
11003
11004    pub fn prepare_restore_change(
11005        &self,
11006        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11007        hunk: &MultiBufferDiffHunk,
11008        cx: &mut App,
11009    ) -> Option<()> {
11010        if hunk.is_created_file() {
11011            return None;
11012        }
11013        let buffer = self.buffer.read(cx);
11014        let diff = buffer.diff_for(hunk.buffer_id)?;
11015        let buffer = buffer.buffer(hunk.buffer_id)?;
11016        let buffer = buffer.read(cx);
11017        let original_text = diff
11018            .read(cx)
11019            .base_text()
11020            .as_rope()
11021            .slice(hunk.diff_base_byte_range.clone());
11022        let buffer_snapshot = buffer.snapshot();
11023        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11024        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11025            probe
11026                .0
11027                .start
11028                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11029                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11030        }) {
11031            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11032            Some(())
11033        } else {
11034            None
11035        }
11036    }
11037
11038    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11039        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11040    }
11041
11042    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11043        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11044    }
11045
11046    fn manipulate_lines<M>(
11047        &mut self,
11048        window: &mut Window,
11049        cx: &mut Context<Self>,
11050        mut manipulate: M,
11051    ) where
11052        M: FnMut(&str) -> LineManipulationResult,
11053    {
11054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11055
11056        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11057        let buffer = self.buffer.read(cx).snapshot(cx);
11058
11059        let mut edits = Vec::new();
11060
11061        let selections = self.selections.all::<Point>(&display_map);
11062        let mut selections = selections.iter().peekable();
11063        let mut contiguous_row_selections = Vec::new();
11064        let mut new_selections = Vec::new();
11065        let mut added_lines = 0;
11066        let mut removed_lines = 0;
11067
11068        while let Some(selection) = selections.next() {
11069            let (start_row, end_row) = consume_contiguous_rows(
11070                &mut contiguous_row_selections,
11071                selection,
11072                &display_map,
11073                &mut selections,
11074            );
11075
11076            let start_point = Point::new(start_row.0, 0);
11077            let end_point = Point::new(
11078                end_row.previous_row().0,
11079                buffer.line_len(end_row.previous_row()),
11080            );
11081            let text = buffer
11082                .text_for_range(start_point..end_point)
11083                .collect::<String>();
11084
11085            let LineManipulationResult {
11086                new_text,
11087                line_count_before,
11088                line_count_after,
11089            } = manipulate(&text);
11090
11091            edits.push((start_point..end_point, new_text));
11092
11093            // Selections must change based on added and removed line count
11094            let start_row =
11095                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11096            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11097            new_selections.push(Selection {
11098                id: selection.id,
11099                start: start_row,
11100                end: end_row,
11101                goal: SelectionGoal::None,
11102                reversed: selection.reversed,
11103            });
11104
11105            if line_count_after > line_count_before {
11106                added_lines += line_count_after - line_count_before;
11107            } else if line_count_before > line_count_after {
11108                removed_lines += line_count_before - line_count_after;
11109            }
11110        }
11111
11112        self.transact(window, cx, |this, window, cx| {
11113            let buffer = this.buffer.update(cx, |buffer, cx| {
11114                buffer.edit(edits, None, cx);
11115                buffer.snapshot(cx)
11116            });
11117
11118            // Recalculate offsets on newly edited buffer
11119            let new_selections = new_selections
11120                .iter()
11121                .map(|s| {
11122                    let start_point = Point::new(s.start.0, 0);
11123                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11124                    Selection {
11125                        id: s.id,
11126                        start: buffer.point_to_offset(start_point),
11127                        end: buffer.point_to_offset(end_point),
11128                        goal: s.goal,
11129                        reversed: s.reversed,
11130                    }
11131                })
11132                .collect();
11133
11134            this.change_selections(Default::default(), window, cx, |s| {
11135                s.select(new_selections);
11136            });
11137
11138            this.request_autoscroll(Autoscroll::fit(), cx);
11139        });
11140    }
11141
11142    fn manipulate_immutable_lines<Fn>(
11143        &mut self,
11144        window: &mut Window,
11145        cx: &mut Context<Self>,
11146        mut callback: Fn,
11147    ) where
11148        Fn: FnMut(&mut Vec<&str>),
11149    {
11150        self.manipulate_lines(window, cx, |text| {
11151            let mut lines: Vec<&str> = text.split('\n').collect();
11152            let line_count_before = lines.len();
11153
11154            callback(&mut lines);
11155
11156            LineManipulationResult {
11157                new_text: lines.join("\n"),
11158                line_count_before,
11159                line_count_after: lines.len(),
11160            }
11161        });
11162    }
11163
11164    fn manipulate_mutable_lines<Fn>(
11165        &mut self,
11166        window: &mut Window,
11167        cx: &mut Context<Self>,
11168        mut callback: Fn,
11169    ) where
11170        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11171    {
11172        self.manipulate_lines(window, cx, |text| {
11173            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11174            let line_count_before = lines.len();
11175
11176            callback(&mut lines);
11177
11178            LineManipulationResult {
11179                new_text: lines.join("\n"),
11180                line_count_before,
11181                line_count_after: lines.len(),
11182            }
11183        });
11184    }
11185
11186    pub fn convert_indentation_to_spaces(
11187        &mut self,
11188        _: &ConvertIndentationToSpaces,
11189        window: &mut Window,
11190        cx: &mut Context<Self>,
11191    ) {
11192        let settings = self.buffer.read(cx).language_settings(cx);
11193        let tab_size = settings.tab_size.get() as usize;
11194
11195        self.manipulate_mutable_lines(window, cx, |lines| {
11196            // Allocates a reasonably sized scratch buffer once for the whole loop
11197            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11198            // Avoids recomputing spaces that could be inserted many times
11199            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11200                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11201                .collect();
11202
11203            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11204                let mut chars = line.as_ref().chars();
11205                let mut col = 0;
11206                let mut changed = false;
11207
11208                for ch in chars.by_ref() {
11209                    match ch {
11210                        ' ' => {
11211                            reindented_line.push(' ');
11212                            col += 1;
11213                        }
11214                        '\t' => {
11215                            // \t are converted to spaces depending on the current column
11216                            let spaces_len = tab_size - (col % tab_size);
11217                            reindented_line.extend(&space_cache[spaces_len - 1]);
11218                            col += spaces_len;
11219                            changed = true;
11220                        }
11221                        _ => {
11222                            // If we dont append before break, the character is consumed
11223                            reindented_line.push(ch);
11224                            break;
11225                        }
11226                    }
11227                }
11228
11229                if !changed {
11230                    reindented_line.clear();
11231                    continue;
11232                }
11233                // Append the rest of the line and replace old reference with new one
11234                reindented_line.extend(chars);
11235                *line = Cow::Owned(reindented_line.clone());
11236                reindented_line.clear();
11237            }
11238        });
11239    }
11240
11241    pub fn convert_indentation_to_tabs(
11242        &mut self,
11243        _: &ConvertIndentationToTabs,
11244        window: &mut Window,
11245        cx: &mut Context<Self>,
11246    ) {
11247        let settings = self.buffer.read(cx).language_settings(cx);
11248        let tab_size = settings.tab_size.get() as usize;
11249
11250        self.manipulate_mutable_lines(window, cx, |lines| {
11251            // Allocates a reasonably sized buffer once for the whole loop
11252            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11253            // Avoids recomputing spaces that could be inserted many times
11254            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11255                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11256                .collect();
11257
11258            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11259                let mut chars = line.chars();
11260                let mut spaces_count = 0;
11261                let mut first_non_indent_char = None;
11262                let mut changed = false;
11263
11264                for ch in chars.by_ref() {
11265                    match ch {
11266                        ' ' => {
11267                            // Keep track of spaces. Append \t when we reach tab_size
11268                            spaces_count += 1;
11269                            changed = true;
11270                            if spaces_count == tab_size {
11271                                reindented_line.push('\t');
11272                                spaces_count = 0;
11273                            }
11274                        }
11275                        '\t' => {
11276                            reindented_line.push('\t');
11277                            spaces_count = 0;
11278                        }
11279                        _ => {
11280                            // Dont append it yet, we might have remaining spaces
11281                            first_non_indent_char = Some(ch);
11282                            break;
11283                        }
11284                    }
11285                }
11286
11287                if !changed {
11288                    reindented_line.clear();
11289                    continue;
11290                }
11291                // Remaining spaces that didn't make a full tab stop
11292                if spaces_count > 0 {
11293                    reindented_line.extend(&space_cache[spaces_count - 1]);
11294                }
11295                // If we consume an extra character that was not indentation, add it back
11296                if let Some(extra_char) = first_non_indent_char {
11297                    reindented_line.push(extra_char);
11298                }
11299                // Append the rest of the line and replace old reference with new one
11300                reindented_line.extend(chars);
11301                *line = Cow::Owned(reindented_line.clone());
11302                reindented_line.clear();
11303            }
11304        });
11305    }
11306
11307    pub fn convert_to_upper_case(
11308        &mut self,
11309        _: &ConvertToUpperCase,
11310        window: &mut Window,
11311        cx: &mut Context<Self>,
11312    ) {
11313        self.manipulate_text(window, cx, |text| text.to_uppercase())
11314    }
11315
11316    pub fn convert_to_lower_case(
11317        &mut self,
11318        _: &ConvertToLowerCase,
11319        window: &mut Window,
11320        cx: &mut Context<Self>,
11321    ) {
11322        self.manipulate_text(window, cx, |text| text.to_lowercase())
11323    }
11324
11325    pub fn convert_to_title_case(
11326        &mut self,
11327        _: &ConvertToTitleCase,
11328        window: &mut Window,
11329        cx: &mut Context<Self>,
11330    ) {
11331        self.manipulate_text(window, cx, |text| {
11332            text.split('\n')
11333                .map(|line| line.to_case(Case::Title))
11334                .join("\n")
11335        })
11336    }
11337
11338    pub fn convert_to_snake_case(
11339        &mut self,
11340        _: &ConvertToSnakeCase,
11341        window: &mut Window,
11342        cx: &mut Context<Self>,
11343    ) {
11344        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11345    }
11346
11347    pub fn convert_to_kebab_case(
11348        &mut self,
11349        _: &ConvertToKebabCase,
11350        window: &mut Window,
11351        cx: &mut Context<Self>,
11352    ) {
11353        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11354    }
11355
11356    pub fn convert_to_upper_camel_case(
11357        &mut self,
11358        _: &ConvertToUpperCamelCase,
11359        window: &mut Window,
11360        cx: &mut Context<Self>,
11361    ) {
11362        self.manipulate_text(window, cx, |text| {
11363            text.split('\n')
11364                .map(|line| line.to_case(Case::UpperCamel))
11365                .join("\n")
11366        })
11367    }
11368
11369    pub fn convert_to_lower_camel_case(
11370        &mut self,
11371        _: &ConvertToLowerCamelCase,
11372        window: &mut Window,
11373        cx: &mut Context<Self>,
11374    ) {
11375        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11376    }
11377
11378    pub fn convert_to_opposite_case(
11379        &mut self,
11380        _: &ConvertToOppositeCase,
11381        window: &mut Window,
11382        cx: &mut Context<Self>,
11383    ) {
11384        self.manipulate_text(window, cx, |text| {
11385            text.chars()
11386                .fold(String::with_capacity(text.len()), |mut t, c| {
11387                    if c.is_uppercase() {
11388                        t.extend(c.to_lowercase());
11389                    } else {
11390                        t.extend(c.to_uppercase());
11391                    }
11392                    t
11393                })
11394        })
11395    }
11396
11397    pub fn convert_to_sentence_case(
11398        &mut self,
11399        _: &ConvertToSentenceCase,
11400        window: &mut Window,
11401        cx: &mut Context<Self>,
11402    ) {
11403        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11404    }
11405
11406    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11407        self.manipulate_text(window, cx, |text| {
11408            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11409            if has_upper_case_characters {
11410                text.to_lowercase()
11411            } else {
11412                text.to_uppercase()
11413            }
11414        })
11415    }
11416
11417    pub fn convert_to_rot13(
11418        &mut self,
11419        _: &ConvertToRot13,
11420        window: &mut Window,
11421        cx: &mut Context<Self>,
11422    ) {
11423        self.manipulate_text(window, cx, |text| {
11424            text.chars()
11425                .map(|c| match c {
11426                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11427                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11428                    _ => c,
11429                })
11430                .collect()
11431        })
11432    }
11433
11434    pub fn convert_to_rot47(
11435        &mut self,
11436        _: &ConvertToRot47,
11437        window: &mut Window,
11438        cx: &mut Context<Self>,
11439    ) {
11440        self.manipulate_text(window, cx, |text| {
11441            text.chars()
11442                .map(|c| {
11443                    let code_point = c as u32;
11444                    if code_point >= 33 && code_point <= 126 {
11445                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11446                    }
11447                    c
11448                })
11449                .collect()
11450        })
11451    }
11452
11453    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11454    where
11455        Fn: FnMut(&str) -> String,
11456    {
11457        let buffer = self.buffer.read(cx).snapshot(cx);
11458
11459        let mut new_selections = Vec::new();
11460        let mut edits = Vec::new();
11461        let mut selection_adjustment = 0i32;
11462
11463        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11464            let selection_is_empty = selection.is_empty();
11465
11466            let (start, end) = if selection_is_empty {
11467                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11468                (word_range.start, word_range.end)
11469            } else {
11470                (
11471                    buffer.point_to_offset(selection.start),
11472                    buffer.point_to_offset(selection.end),
11473                )
11474            };
11475
11476            let text = buffer.text_for_range(start..end).collect::<String>();
11477            let old_length = text.len() as i32;
11478            let text = callback(&text);
11479
11480            new_selections.push(Selection {
11481                start: (start as i32 - selection_adjustment) as usize,
11482                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11483                goal: SelectionGoal::None,
11484                id: selection.id,
11485                reversed: selection.reversed,
11486            });
11487
11488            selection_adjustment += old_length - text.len() as i32;
11489
11490            edits.push((start..end, text));
11491        }
11492
11493        self.transact(window, cx, |this, window, cx| {
11494            this.buffer.update(cx, |buffer, cx| {
11495                buffer.edit(edits, None, cx);
11496            });
11497
11498            this.change_selections(Default::default(), window, cx, |s| {
11499                s.select(new_selections);
11500            });
11501
11502            this.request_autoscroll(Autoscroll::fit(), cx);
11503        });
11504    }
11505
11506    pub fn move_selection_on_drop(
11507        &mut self,
11508        selection: &Selection<Anchor>,
11509        target: DisplayPoint,
11510        is_cut: bool,
11511        window: &mut Window,
11512        cx: &mut Context<Self>,
11513    ) {
11514        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11515        let buffer = display_map.buffer_snapshot();
11516        let mut edits = Vec::new();
11517        let insert_point = display_map
11518            .clip_point(target, Bias::Left)
11519            .to_point(&display_map);
11520        let text = buffer
11521            .text_for_range(selection.start..selection.end)
11522            .collect::<String>();
11523        if is_cut {
11524            edits.push(((selection.start..selection.end), String::new()));
11525        }
11526        let insert_anchor = buffer.anchor_before(insert_point);
11527        edits.push(((insert_anchor..insert_anchor), text));
11528        let last_edit_start = insert_anchor.bias_left(buffer);
11529        let last_edit_end = insert_anchor.bias_right(buffer);
11530        self.transact(window, cx, |this, window, cx| {
11531            this.buffer.update(cx, |buffer, cx| {
11532                buffer.edit(edits, None, cx);
11533            });
11534            this.change_selections(Default::default(), window, cx, |s| {
11535                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11536            });
11537        });
11538    }
11539
11540    pub fn clear_selection_drag_state(&mut self) {
11541        self.selection_drag_state = SelectionDragState::None;
11542    }
11543
11544    pub fn duplicate(
11545        &mut self,
11546        upwards: bool,
11547        whole_lines: bool,
11548        window: &mut Window,
11549        cx: &mut Context<Self>,
11550    ) {
11551        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11552
11553        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11554        let buffer = display_map.buffer_snapshot();
11555        let selections = self.selections.all::<Point>(&display_map);
11556
11557        let mut edits = Vec::new();
11558        let mut selections_iter = selections.iter().peekable();
11559        while let Some(selection) = selections_iter.next() {
11560            let mut rows = selection.spanned_rows(false, &display_map);
11561            // duplicate line-wise
11562            if whole_lines || selection.start == selection.end {
11563                // Avoid duplicating the same lines twice.
11564                while let Some(next_selection) = selections_iter.peek() {
11565                    let next_rows = next_selection.spanned_rows(false, &display_map);
11566                    if next_rows.start < rows.end {
11567                        rows.end = next_rows.end;
11568                        selections_iter.next().unwrap();
11569                    } else {
11570                        break;
11571                    }
11572                }
11573
11574                // Copy the text from the selected row region and splice it either at the start
11575                // or end of the region.
11576                let start = Point::new(rows.start.0, 0);
11577                let end = Point::new(
11578                    rows.end.previous_row().0,
11579                    buffer.line_len(rows.end.previous_row()),
11580                );
11581
11582                let mut text = buffer.text_for_range(start..end).collect::<String>();
11583
11584                let insert_location = if upwards {
11585                    // When duplicating upward, we need to insert before the current line.
11586                    // If we're on the last line and it doesn't end with a newline,
11587                    // we need to add a newline before the duplicated content.
11588                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11589                        && buffer.max_point().column > 0
11590                        && !text.ends_with('\n');
11591
11592                    if needs_leading_newline {
11593                        text.insert(0, '\n');
11594                        end
11595                    } else {
11596                        text.push('\n');
11597                        Point::new(rows.start.0, 0)
11598                    }
11599                } else {
11600                    text.push('\n');
11601                    start
11602                };
11603                edits.push((insert_location..insert_location, text));
11604            } else {
11605                // duplicate character-wise
11606                let start = selection.start;
11607                let end = selection.end;
11608                let text = buffer.text_for_range(start..end).collect::<String>();
11609                edits.push((selection.end..selection.end, text));
11610            }
11611        }
11612
11613        self.transact(window, cx, |this, window, cx| {
11614            this.buffer.update(cx, |buffer, cx| {
11615                buffer.edit(edits, None, cx);
11616            });
11617
11618            // When duplicating upward with whole lines, move the cursor to the duplicated line
11619            if upwards && whole_lines {
11620                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11621
11622                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11623                    let mut new_ranges = Vec::new();
11624                    let selections = s.all::<Point>(&display_map);
11625                    let mut selections_iter = selections.iter().peekable();
11626
11627                    while let Some(first_selection) = selections_iter.next() {
11628                        // Group contiguous selections together to find the total row span
11629                        let mut group_selections = vec![first_selection];
11630                        let mut rows = first_selection.spanned_rows(false, &display_map);
11631
11632                        while let Some(next_selection) = selections_iter.peek() {
11633                            let next_rows = next_selection.spanned_rows(false, &display_map);
11634                            if next_rows.start < rows.end {
11635                                rows.end = next_rows.end;
11636                                group_selections.push(selections_iter.next().unwrap());
11637                            } else {
11638                                break;
11639                            }
11640                        }
11641
11642                        let row_count = rows.end.0 - rows.start.0;
11643
11644                        // Move all selections in this group up by the total number of duplicated rows
11645                        for selection in group_selections {
11646                            let new_start = Point::new(
11647                                selection.start.row.saturating_sub(row_count),
11648                                selection.start.column,
11649                            );
11650
11651                            let new_end = Point::new(
11652                                selection.end.row.saturating_sub(row_count),
11653                                selection.end.column,
11654                            );
11655
11656                            new_ranges.push(new_start..new_end);
11657                        }
11658                    }
11659
11660                    s.select_ranges(new_ranges);
11661                });
11662            }
11663
11664            this.request_autoscroll(Autoscroll::fit(), cx);
11665        });
11666    }
11667
11668    pub fn duplicate_line_up(
11669        &mut self,
11670        _: &DuplicateLineUp,
11671        window: &mut Window,
11672        cx: &mut Context<Self>,
11673    ) {
11674        self.duplicate(true, true, window, cx);
11675    }
11676
11677    pub fn duplicate_line_down(
11678        &mut self,
11679        _: &DuplicateLineDown,
11680        window: &mut Window,
11681        cx: &mut Context<Self>,
11682    ) {
11683        self.duplicate(false, true, window, cx);
11684    }
11685
11686    pub fn duplicate_selection(
11687        &mut self,
11688        _: &DuplicateSelection,
11689        window: &mut Window,
11690        cx: &mut Context<Self>,
11691    ) {
11692        self.duplicate(false, false, window, cx);
11693    }
11694
11695    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11696        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11697        if self.mode.is_single_line() {
11698            cx.propagate();
11699            return;
11700        }
11701
11702        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11703        let buffer = self.buffer.read(cx).snapshot(cx);
11704
11705        let mut edits = Vec::new();
11706        let mut unfold_ranges = Vec::new();
11707        let mut refold_creases = Vec::new();
11708
11709        let selections = self.selections.all::<Point>(&display_map);
11710        let mut selections = selections.iter().peekable();
11711        let mut contiguous_row_selections = Vec::new();
11712        let mut new_selections = Vec::new();
11713
11714        while let Some(selection) = selections.next() {
11715            // Find all the selections that span a contiguous row range
11716            let (start_row, end_row) = consume_contiguous_rows(
11717                &mut contiguous_row_selections,
11718                selection,
11719                &display_map,
11720                &mut selections,
11721            );
11722
11723            // Move the text spanned by the row range to be before the line preceding the row range
11724            if start_row.0 > 0 {
11725                let range_to_move = Point::new(
11726                    start_row.previous_row().0,
11727                    buffer.line_len(start_row.previous_row()),
11728                )
11729                    ..Point::new(
11730                        end_row.previous_row().0,
11731                        buffer.line_len(end_row.previous_row()),
11732                    );
11733                let insertion_point = display_map
11734                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11735                    .0;
11736
11737                // Don't move lines across excerpts
11738                if buffer
11739                    .excerpt_containing(insertion_point..range_to_move.end)
11740                    .is_some()
11741                {
11742                    let text = buffer
11743                        .text_for_range(range_to_move.clone())
11744                        .flat_map(|s| s.chars())
11745                        .skip(1)
11746                        .chain(['\n'])
11747                        .collect::<String>();
11748
11749                    edits.push((
11750                        buffer.anchor_after(range_to_move.start)
11751                            ..buffer.anchor_before(range_to_move.end),
11752                        String::new(),
11753                    ));
11754                    let insertion_anchor = buffer.anchor_after(insertion_point);
11755                    edits.push((insertion_anchor..insertion_anchor, text));
11756
11757                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11758
11759                    // Move selections up
11760                    new_selections.extend(contiguous_row_selections.drain(..).map(
11761                        |mut selection| {
11762                            selection.start.row -= row_delta;
11763                            selection.end.row -= row_delta;
11764                            selection
11765                        },
11766                    ));
11767
11768                    // Move folds up
11769                    unfold_ranges.push(range_to_move.clone());
11770                    for fold in display_map.folds_in_range(
11771                        buffer.anchor_before(range_to_move.start)
11772                            ..buffer.anchor_after(range_to_move.end),
11773                    ) {
11774                        let mut start = fold.range.start.to_point(&buffer);
11775                        let mut end = fold.range.end.to_point(&buffer);
11776                        start.row -= row_delta;
11777                        end.row -= row_delta;
11778                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11779                    }
11780                }
11781            }
11782
11783            // If we didn't move line(s), preserve the existing selections
11784            new_selections.append(&mut contiguous_row_selections);
11785        }
11786
11787        self.transact(window, cx, |this, window, cx| {
11788            this.unfold_ranges(&unfold_ranges, true, true, cx);
11789            this.buffer.update(cx, |buffer, cx| {
11790                for (range, text) in edits {
11791                    buffer.edit([(range, text)], None, cx);
11792                }
11793            });
11794            this.fold_creases(refold_creases, true, window, cx);
11795            this.change_selections(Default::default(), window, cx, |s| {
11796                s.select(new_selections);
11797            })
11798        });
11799    }
11800
11801    pub fn move_line_down(
11802        &mut self,
11803        _: &MoveLineDown,
11804        window: &mut Window,
11805        cx: &mut Context<Self>,
11806    ) {
11807        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11808        if self.mode.is_single_line() {
11809            cx.propagate();
11810            return;
11811        }
11812
11813        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11814        let buffer = self.buffer.read(cx).snapshot(cx);
11815
11816        let mut edits = Vec::new();
11817        let mut unfold_ranges = Vec::new();
11818        let mut refold_creases = Vec::new();
11819
11820        let selections = self.selections.all::<Point>(&display_map);
11821        let mut selections = selections.iter().peekable();
11822        let mut contiguous_row_selections = Vec::new();
11823        let mut new_selections = Vec::new();
11824
11825        while let Some(selection) = selections.next() {
11826            // Find all the selections that span a contiguous row range
11827            let (start_row, end_row) = consume_contiguous_rows(
11828                &mut contiguous_row_selections,
11829                selection,
11830                &display_map,
11831                &mut selections,
11832            );
11833
11834            // Move the text spanned by the row range to be after the last line of the row range
11835            if end_row.0 <= buffer.max_point().row {
11836                let range_to_move =
11837                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11838                let insertion_point = display_map
11839                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11840                    .0;
11841
11842                // Don't move lines across excerpt boundaries
11843                if buffer
11844                    .excerpt_containing(range_to_move.start..insertion_point)
11845                    .is_some()
11846                {
11847                    let mut text = String::from("\n");
11848                    text.extend(buffer.text_for_range(range_to_move.clone()));
11849                    text.pop(); // Drop trailing newline
11850                    edits.push((
11851                        buffer.anchor_after(range_to_move.start)
11852                            ..buffer.anchor_before(range_to_move.end),
11853                        String::new(),
11854                    ));
11855                    let insertion_anchor = buffer.anchor_after(insertion_point);
11856                    edits.push((insertion_anchor..insertion_anchor, text));
11857
11858                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11859
11860                    // Move selections down
11861                    new_selections.extend(contiguous_row_selections.drain(..).map(
11862                        |mut selection| {
11863                            selection.start.row += row_delta;
11864                            selection.end.row += row_delta;
11865                            selection
11866                        },
11867                    ));
11868
11869                    // Move folds down
11870                    unfold_ranges.push(range_to_move.clone());
11871                    for fold in display_map.folds_in_range(
11872                        buffer.anchor_before(range_to_move.start)
11873                            ..buffer.anchor_after(range_to_move.end),
11874                    ) {
11875                        let mut start = fold.range.start.to_point(&buffer);
11876                        let mut end = fold.range.end.to_point(&buffer);
11877                        start.row += row_delta;
11878                        end.row += row_delta;
11879                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11880                    }
11881                }
11882            }
11883
11884            // If we didn't move line(s), preserve the existing selections
11885            new_selections.append(&mut contiguous_row_selections);
11886        }
11887
11888        self.transact(window, cx, |this, window, cx| {
11889            this.unfold_ranges(&unfold_ranges, true, true, cx);
11890            this.buffer.update(cx, |buffer, cx| {
11891                for (range, text) in edits {
11892                    buffer.edit([(range, text)], None, cx);
11893                }
11894            });
11895            this.fold_creases(refold_creases, true, window, cx);
11896            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11897        });
11898    }
11899
11900    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11901        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11902        let text_layout_details = &self.text_layout_details(window);
11903        self.transact(window, cx, |this, window, cx| {
11904            let edits = this.change_selections(Default::default(), window, cx, |s| {
11905                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11906                s.move_with(|display_map, selection| {
11907                    if !selection.is_empty() {
11908                        return;
11909                    }
11910
11911                    let mut head = selection.head();
11912                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11913                    if head.column() == display_map.line_len(head.row()) {
11914                        transpose_offset = display_map
11915                            .buffer_snapshot()
11916                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11917                    }
11918
11919                    if transpose_offset == 0 {
11920                        return;
11921                    }
11922
11923                    *head.column_mut() += 1;
11924                    head = display_map.clip_point(head, Bias::Right);
11925                    let goal = SelectionGoal::HorizontalPosition(
11926                        display_map
11927                            .x_for_display_point(head, text_layout_details)
11928                            .into(),
11929                    );
11930                    selection.collapse_to(head, goal);
11931
11932                    let transpose_start = display_map
11933                        .buffer_snapshot()
11934                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11935                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11936                        let transpose_end = display_map
11937                            .buffer_snapshot()
11938                            .clip_offset(transpose_offset + 1, Bias::Right);
11939                        if let Some(ch) = display_map
11940                            .buffer_snapshot()
11941                            .chars_at(transpose_start)
11942                            .next()
11943                        {
11944                            edits.push((transpose_start..transpose_offset, String::new()));
11945                            edits.push((transpose_end..transpose_end, ch.to_string()));
11946                        }
11947                    }
11948                });
11949                edits
11950            });
11951            this.buffer
11952                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11953            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
11954            this.change_selections(Default::default(), window, cx, |s| {
11955                s.select(selections);
11956            });
11957        });
11958    }
11959
11960    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11961        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11962        if self.mode.is_single_line() {
11963            cx.propagate();
11964            return;
11965        }
11966
11967        self.rewrap_impl(RewrapOptions::default(), cx)
11968    }
11969
11970    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11971        let buffer = self.buffer.read(cx).snapshot(cx);
11972        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11973
11974        #[derive(Clone, Debug, PartialEq)]
11975        enum CommentFormat {
11976            /// single line comment, with prefix for line
11977            Line(String),
11978            /// single line within a block comment, with prefix for line
11979            BlockLine(String),
11980            /// a single line of a block comment that includes the initial delimiter
11981            BlockCommentWithStart(BlockCommentConfig),
11982            /// a single line of a block comment that includes the ending delimiter
11983            BlockCommentWithEnd(BlockCommentConfig),
11984        }
11985
11986        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11987        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11988            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11989                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11990                .peekable();
11991
11992            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11993                row
11994            } else {
11995                return Vec::new();
11996            };
11997
11998            let language_settings = buffer.language_settings_at(selection.head(), cx);
11999            let language_scope = buffer.language_scope_at(selection.head());
12000
12001            let indent_and_prefix_for_row =
12002                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12003                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12004                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12005                        &language_scope
12006                    {
12007                        let indent_end = Point::new(row, indent.len);
12008                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12009                        let line_text_after_indent = buffer
12010                            .text_for_range(indent_end..line_end)
12011                            .collect::<String>();
12012
12013                        let is_within_comment_override = buffer
12014                            .language_scope_at(indent_end)
12015                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12016                        let comment_delimiters = if is_within_comment_override {
12017                            // we are within a comment syntax node, but we don't
12018                            // yet know what kind of comment: block, doc or line
12019                            match (
12020                                language_scope.documentation_comment(),
12021                                language_scope.block_comment(),
12022                            ) {
12023                                (Some(config), _) | (_, Some(config))
12024                                    if buffer.contains_str_at(indent_end, &config.start) =>
12025                                {
12026                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12027                                }
12028                                (Some(config), _) | (_, Some(config))
12029                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12030                                {
12031                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12032                                }
12033                                (Some(config), _) | (_, Some(config))
12034                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12035                                {
12036                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12037                                }
12038                                (_, _) => language_scope
12039                                    .line_comment_prefixes()
12040                                    .iter()
12041                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12042                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12043                            }
12044                        } else {
12045                            // we not in an overridden comment node, but we may
12046                            // be within a non-overridden line comment node
12047                            language_scope
12048                                .line_comment_prefixes()
12049                                .iter()
12050                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12051                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12052                        };
12053
12054                        let rewrap_prefix = language_scope
12055                            .rewrap_prefixes()
12056                            .iter()
12057                            .find_map(|prefix_regex| {
12058                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12059                                    if mat.start() == 0 {
12060                                        Some(mat.as_str().to_string())
12061                                    } else {
12062                                        None
12063                                    }
12064                                })
12065                            })
12066                            .flatten();
12067                        (comment_delimiters, rewrap_prefix)
12068                    } else {
12069                        (None, None)
12070                    };
12071                    (indent, comment_prefix, rewrap_prefix)
12072                };
12073
12074            let mut ranges = Vec::new();
12075            let from_empty_selection = selection.is_empty();
12076
12077            let mut current_range_start = first_row;
12078            let mut prev_row = first_row;
12079            let (
12080                mut current_range_indent,
12081                mut current_range_comment_delimiters,
12082                mut current_range_rewrap_prefix,
12083            ) = indent_and_prefix_for_row(first_row);
12084
12085            for row in non_blank_rows_iter.skip(1) {
12086                let has_paragraph_break = row > prev_row + 1;
12087
12088                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12089                    indent_and_prefix_for_row(row);
12090
12091                let has_indent_change = row_indent != current_range_indent;
12092                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12093
12094                let has_boundary_change = has_comment_change
12095                    || row_rewrap_prefix.is_some()
12096                    || (has_indent_change && current_range_comment_delimiters.is_some());
12097
12098                if has_paragraph_break || has_boundary_change {
12099                    ranges.push((
12100                        language_settings.clone(),
12101                        Point::new(current_range_start, 0)
12102                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12103                        current_range_indent,
12104                        current_range_comment_delimiters.clone(),
12105                        current_range_rewrap_prefix.clone(),
12106                        from_empty_selection,
12107                    ));
12108                    current_range_start = row;
12109                    current_range_indent = row_indent;
12110                    current_range_comment_delimiters = row_comment_delimiters;
12111                    current_range_rewrap_prefix = row_rewrap_prefix;
12112                }
12113                prev_row = row;
12114            }
12115
12116            ranges.push((
12117                language_settings.clone(),
12118                Point::new(current_range_start, 0)
12119                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12120                current_range_indent,
12121                current_range_comment_delimiters,
12122                current_range_rewrap_prefix,
12123                from_empty_selection,
12124            ));
12125
12126            ranges
12127        });
12128
12129        let mut edits = Vec::new();
12130        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12131
12132        for (
12133            language_settings,
12134            wrap_range,
12135            mut indent_size,
12136            comment_prefix,
12137            rewrap_prefix,
12138            from_empty_selection,
12139        ) in wrap_ranges
12140        {
12141            let mut start_row = wrap_range.start.row;
12142            let mut end_row = wrap_range.end.row;
12143
12144            // Skip selections that overlap with a range that has already been rewrapped.
12145            let selection_range = start_row..end_row;
12146            if rewrapped_row_ranges
12147                .iter()
12148                .any(|range| range.overlaps(&selection_range))
12149            {
12150                continue;
12151            }
12152
12153            let tab_size = language_settings.tab_size;
12154
12155            let (line_prefix, inside_comment) = match &comment_prefix {
12156                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12157                    (Some(prefix.as_str()), true)
12158                }
12159                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12160                    (Some(prefix.as_ref()), true)
12161                }
12162                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12163                    start: _,
12164                    end: _,
12165                    prefix,
12166                    tab_size,
12167                })) => {
12168                    indent_size.len += tab_size;
12169                    (Some(prefix.as_ref()), true)
12170                }
12171                None => (None, false),
12172            };
12173            let indent_prefix = indent_size.chars().collect::<String>();
12174            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12175
12176            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12177                RewrapBehavior::InComments => inside_comment,
12178                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12179                RewrapBehavior::Anywhere => true,
12180            };
12181
12182            let should_rewrap = options.override_language_settings
12183                || allow_rewrap_based_on_language
12184                || self.hard_wrap.is_some();
12185            if !should_rewrap {
12186                continue;
12187            }
12188
12189            if from_empty_selection {
12190                'expand_upwards: while start_row > 0 {
12191                    let prev_row = start_row - 1;
12192                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12193                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12194                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12195                    {
12196                        start_row = prev_row;
12197                    } else {
12198                        break 'expand_upwards;
12199                    }
12200                }
12201
12202                'expand_downwards: while end_row < buffer.max_point().row {
12203                    let next_row = end_row + 1;
12204                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12205                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12206                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12207                    {
12208                        end_row = next_row;
12209                    } else {
12210                        break 'expand_downwards;
12211                    }
12212                }
12213            }
12214
12215            let start = Point::new(start_row, 0);
12216            let start_offset = ToOffset::to_offset(&start, &buffer);
12217            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12218            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12219            let mut first_line_delimiter = None;
12220            let mut last_line_delimiter = None;
12221            let Some(lines_without_prefixes) = selection_text
12222                .lines()
12223                .enumerate()
12224                .map(|(ix, line)| {
12225                    let line_trimmed = line.trim_start();
12226                    if rewrap_prefix.is_some() && ix > 0 {
12227                        Ok(line_trimmed)
12228                    } else if let Some(
12229                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12230                            start,
12231                            prefix,
12232                            end,
12233                            tab_size,
12234                        })
12235                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12236                            start,
12237                            prefix,
12238                            end,
12239                            tab_size,
12240                        }),
12241                    ) = &comment_prefix
12242                    {
12243                        let line_trimmed = line_trimmed
12244                            .strip_prefix(start.as_ref())
12245                            .map(|s| {
12246                                let mut indent_size = indent_size;
12247                                indent_size.len -= tab_size;
12248                                let indent_prefix: String = indent_size.chars().collect();
12249                                first_line_delimiter = Some((indent_prefix, start));
12250                                s.trim_start()
12251                            })
12252                            .unwrap_or(line_trimmed);
12253                        let line_trimmed = line_trimmed
12254                            .strip_suffix(end.as_ref())
12255                            .map(|s| {
12256                                last_line_delimiter = Some(end);
12257                                s.trim_end()
12258                            })
12259                            .unwrap_or(line_trimmed);
12260                        let line_trimmed = line_trimmed
12261                            .strip_prefix(prefix.as_ref())
12262                            .unwrap_or(line_trimmed);
12263                        Ok(line_trimmed)
12264                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12265                        line_trimmed.strip_prefix(prefix).with_context(|| {
12266                            format!("line did not start with prefix {prefix:?}: {line:?}")
12267                        })
12268                    } else {
12269                        line_trimmed
12270                            .strip_prefix(&line_prefix.trim_start())
12271                            .with_context(|| {
12272                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12273                            })
12274                    }
12275                })
12276                .collect::<Result<Vec<_>, _>>()
12277                .log_err()
12278            else {
12279                continue;
12280            };
12281
12282            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12283                buffer
12284                    .language_settings_at(Point::new(start_row, 0), cx)
12285                    .preferred_line_length as usize
12286            });
12287
12288            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12289                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12290            } else {
12291                line_prefix.clone()
12292            };
12293
12294            let wrapped_text = {
12295                let mut wrapped_text = wrap_with_prefix(
12296                    line_prefix,
12297                    subsequent_lines_prefix,
12298                    lines_without_prefixes.join("\n"),
12299                    wrap_column,
12300                    tab_size,
12301                    options.preserve_existing_whitespace,
12302                );
12303
12304                if let Some((indent, delimiter)) = first_line_delimiter {
12305                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12306                }
12307                if let Some(last_line) = last_line_delimiter {
12308                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12309                }
12310
12311                wrapped_text
12312            };
12313
12314            // TODO: should always use char-based diff while still supporting cursor behavior that
12315            // matches vim.
12316            let mut diff_options = DiffOptions::default();
12317            if options.override_language_settings {
12318                diff_options.max_word_diff_len = 0;
12319                diff_options.max_word_diff_line_count = 0;
12320            } else {
12321                diff_options.max_word_diff_len = usize::MAX;
12322                diff_options.max_word_diff_line_count = usize::MAX;
12323            }
12324
12325            for (old_range, new_text) in
12326                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12327            {
12328                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12329                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12330                edits.push((edit_start..edit_end, new_text));
12331            }
12332
12333            rewrapped_row_ranges.push(start_row..=end_row);
12334        }
12335
12336        self.buffer
12337            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12338    }
12339
12340    pub fn cut_common(
12341        &mut self,
12342        cut_no_selection_line: bool,
12343        window: &mut Window,
12344        cx: &mut Context<Self>,
12345    ) -> ClipboardItem {
12346        let mut text = String::new();
12347        let buffer = self.buffer.read(cx).snapshot(cx);
12348        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12349        let mut clipboard_selections = Vec::with_capacity(selections.len());
12350        {
12351            let max_point = buffer.max_point();
12352            let mut is_first = true;
12353            for selection in &mut selections {
12354                let is_entire_line =
12355                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12356                if is_entire_line {
12357                    selection.start = Point::new(selection.start.row, 0);
12358                    if !selection.is_empty() && selection.end.column == 0 {
12359                        selection.end = cmp::min(max_point, selection.end);
12360                    } else {
12361                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12362                    }
12363                    selection.goal = SelectionGoal::None;
12364                }
12365                if is_first {
12366                    is_first = false;
12367                } else {
12368                    text += "\n";
12369                }
12370                let mut len = 0;
12371                for chunk in buffer.text_for_range(selection.start..selection.end) {
12372                    text.push_str(chunk);
12373                    len += chunk.len();
12374                }
12375                clipboard_selections.push(ClipboardSelection {
12376                    len,
12377                    is_entire_line,
12378                    first_line_indent: buffer
12379                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12380                        .len,
12381                });
12382            }
12383        }
12384
12385        self.transact(window, cx, |this, window, cx| {
12386            this.change_selections(Default::default(), window, cx, |s| {
12387                s.select(selections);
12388            });
12389            this.insert("", window, cx);
12390        });
12391        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12392    }
12393
12394    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12395        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12396        let item = self.cut_common(true, window, cx);
12397        cx.write_to_clipboard(item);
12398    }
12399
12400    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12401        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12402        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12403            s.move_with(|snapshot, sel| {
12404                if sel.is_empty() {
12405                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12406                }
12407                if sel.is_empty() {
12408                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12409                }
12410            });
12411        });
12412        let item = self.cut_common(false, window, cx);
12413        cx.set_global(KillRing(item))
12414    }
12415
12416    pub fn kill_ring_yank(
12417        &mut self,
12418        _: &KillRingYank,
12419        window: &mut Window,
12420        cx: &mut Context<Self>,
12421    ) {
12422        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12423        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12424            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12425                (kill_ring.text().to_string(), kill_ring.metadata_json())
12426            } else {
12427                return;
12428            }
12429        } else {
12430            return;
12431        };
12432        self.do_paste(&text, metadata, false, window, cx);
12433    }
12434
12435    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12436        self.do_copy(true, cx);
12437    }
12438
12439    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12440        self.do_copy(false, cx);
12441    }
12442
12443    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12444        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12445        let buffer = self.buffer.read(cx).read(cx);
12446        let mut text = String::new();
12447
12448        let mut clipboard_selections = Vec::with_capacity(selections.len());
12449        {
12450            let max_point = buffer.max_point();
12451            let mut is_first = true;
12452            for selection in &selections {
12453                let mut start = selection.start;
12454                let mut end = selection.end;
12455                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12456                let mut add_trailing_newline = false;
12457                if is_entire_line {
12458                    start = Point::new(start.row, 0);
12459                    let next_line_start = Point::new(end.row + 1, 0);
12460                    if next_line_start <= max_point {
12461                        end = next_line_start;
12462                    } else {
12463                        // We're on the last line without a trailing newline.
12464                        // Copy to the end of the line and add a newline afterwards.
12465                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12466                        add_trailing_newline = true;
12467                    }
12468                }
12469
12470                let mut trimmed_selections = Vec::new();
12471                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12472                    let row = MultiBufferRow(start.row);
12473                    let first_indent = buffer.indent_size_for_line(row);
12474                    if first_indent.len == 0 || start.column > first_indent.len {
12475                        trimmed_selections.push(start..end);
12476                    } else {
12477                        trimmed_selections.push(
12478                            Point::new(row.0, first_indent.len)
12479                                ..Point::new(row.0, buffer.line_len(row)),
12480                        );
12481                        for row in start.row + 1..=end.row {
12482                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12483                            if row == end.row {
12484                                line_len = end.column;
12485                            }
12486                            if line_len == 0 {
12487                                trimmed_selections
12488                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12489                                continue;
12490                            }
12491                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12492                            if row_indent_size.len >= first_indent.len {
12493                                trimmed_selections.push(
12494                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12495                                );
12496                            } else {
12497                                trimmed_selections.clear();
12498                                trimmed_selections.push(start..end);
12499                                break;
12500                            }
12501                        }
12502                    }
12503                } else {
12504                    trimmed_selections.push(start..end);
12505                }
12506
12507                for trimmed_range in trimmed_selections {
12508                    if is_first {
12509                        is_first = false;
12510                    } else {
12511                        text += "\n";
12512                    }
12513                    let mut len = 0;
12514                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12515                        text.push_str(chunk);
12516                        len += chunk.len();
12517                    }
12518                    if add_trailing_newline {
12519                        text.push('\n');
12520                        len += 1;
12521                    }
12522                    clipboard_selections.push(ClipboardSelection {
12523                        len,
12524                        is_entire_line,
12525                        first_line_indent: buffer
12526                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12527                            .len,
12528                    });
12529                }
12530            }
12531        }
12532
12533        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12534            text,
12535            clipboard_selections,
12536        ));
12537    }
12538
12539    pub fn do_paste(
12540        &mut self,
12541        text: &String,
12542        clipboard_selections: Option<Vec<ClipboardSelection>>,
12543        handle_entire_lines: bool,
12544        window: &mut Window,
12545        cx: &mut Context<Self>,
12546    ) {
12547        if self.read_only(cx) {
12548            return;
12549        }
12550
12551        let clipboard_text = Cow::Borrowed(text.as_str());
12552
12553        self.transact(window, cx, |this, window, cx| {
12554            let had_active_edit_prediction = this.has_active_edit_prediction();
12555            let display_map = this.display_snapshot(cx);
12556            let old_selections = this.selections.all::<usize>(&display_map);
12557            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12558
12559            if let Some(mut clipboard_selections) = clipboard_selections {
12560                let all_selections_were_entire_line =
12561                    clipboard_selections.iter().all(|s| s.is_entire_line);
12562                let first_selection_indent_column =
12563                    clipboard_selections.first().map(|s| s.first_line_indent);
12564                if clipboard_selections.len() != old_selections.len() {
12565                    clipboard_selections.drain(..);
12566                }
12567                let mut auto_indent_on_paste = true;
12568
12569                this.buffer.update(cx, |buffer, cx| {
12570                    let snapshot = buffer.read(cx);
12571                    auto_indent_on_paste = snapshot
12572                        .language_settings_at(cursor_offset, cx)
12573                        .auto_indent_on_paste;
12574
12575                    let mut start_offset = 0;
12576                    let mut edits = Vec::new();
12577                    let mut original_indent_columns = Vec::new();
12578                    for (ix, selection) in old_selections.iter().enumerate() {
12579                        let to_insert;
12580                        let entire_line;
12581                        let original_indent_column;
12582                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12583                            let end_offset = start_offset + clipboard_selection.len;
12584                            to_insert = &clipboard_text[start_offset..end_offset];
12585                            entire_line = clipboard_selection.is_entire_line;
12586                            start_offset = end_offset + 1;
12587                            original_indent_column = Some(clipboard_selection.first_line_indent);
12588                        } else {
12589                            to_insert = &*clipboard_text;
12590                            entire_line = all_selections_were_entire_line;
12591                            original_indent_column = first_selection_indent_column
12592                        }
12593
12594                        let (range, to_insert) =
12595                            if selection.is_empty() && handle_entire_lines && entire_line {
12596                                // If the corresponding selection was empty when this slice of the
12597                                // clipboard text was written, then the entire line containing the
12598                                // selection was copied. If this selection is also currently empty,
12599                                // then paste the line before the current line of the buffer.
12600                                let column = selection.start.to_point(&snapshot).column as usize;
12601                                let line_start = selection.start - column;
12602                                (line_start..line_start, Cow::Borrowed(to_insert))
12603                            } else {
12604                                let language = snapshot.language_at(selection.head());
12605                                let range = selection.range();
12606                                if let Some(language) = language
12607                                    && language.name() == "Markdown".into()
12608                                {
12609                                    edit_for_markdown_paste(
12610                                        &snapshot,
12611                                        range,
12612                                        to_insert,
12613                                        url::Url::parse(to_insert).ok(),
12614                                    )
12615                                } else {
12616                                    (range, Cow::Borrowed(to_insert))
12617                                }
12618                            };
12619
12620                        edits.push((range, to_insert));
12621                        original_indent_columns.push(original_indent_column);
12622                    }
12623                    drop(snapshot);
12624
12625                    buffer.edit(
12626                        edits,
12627                        if auto_indent_on_paste {
12628                            Some(AutoindentMode::Block {
12629                                original_indent_columns,
12630                            })
12631                        } else {
12632                            None
12633                        },
12634                        cx,
12635                    );
12636                });
12637
12638                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12639                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12640            } else {
12641                let url = url::Url::parse(&clipboard_text).ok();
12642
12643                let auto_indent_mode = if !clipboard_text.is_empty() {
12644                    Some(AutoindentMode::Block {
12645                        original_indent_columns: Vec::new(),
12646                    })
12647                } else {
12648                    None
12649                };
12650
12651                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12652                    let snapshot = buffer.snapshot(cx);
12653
12654                    let anchors = old_selections
12655                        .iter()
12656                        .map(|s| {
12657                            let anchor = snapshot.anchor_after(s.head());
12658                            s.map(|_| anchor)
12659                        })
12660                        .collect::<Vec<_>>();
12661
12662                    let mut edits = Vec::new();
12663
12664                    for selection in old_selections.iter() {
12665                        let language = snapshot.language_at(selection.head());
12666                        let range = selection.range();
12667
12668                        let (edit_range, edit_text) = if let Some(language) = language
12669                            && language.name() == "Markdown".into()
12670                        {
12671                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12672                        } else {
12673                            (range, clipboard_text.clone())
12674                        };
12675
12676                        edits.push((edit_range, edit_text));
12677                    }
12678
12679                    drop(snapshot);
12680                    buffer.edit(edits, auto_indent_mode, cx);
12681
12682                    anchors
12683                });
12684
12685                this.change_selections(Default::default(), window, cx, |s| {
12686                    s.select_anchors(selection_anchors);
12687                });
12688            }
12689
12690            let trigger_in_words =
12691                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12692
12693            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12694        });
12695    }
12696
12697    pub fn diff_clipboard_with_selection(
12698        &mut self,
12699        _: &DiffClipboardWithSelection,
12700        window: &mut Window,
12701        cx: &mut Context<Self>,
12702    ) {
12703        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12704
12705        if selections.is_empty() {
12706            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12707            return;
12708        };
12709
12710        let clipboard_text = match cx.read_from_clipboard() {
12711            Some(item) => match item.entries().first() {
12712                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12713                _ => None,
12714            },
12715            None => None,
12716        };
12717
12718        let Some(clipboard_text) = clipboard_text else {
12719            log::warn!("Clipboard doesn't contain text.");
12720            return;
12721        };
12722
12723        window.dispatch_action(
12724            Box::new(DiffClipboardWithSelectionData {
12725                clipboard_text,
12726                editor: cx.entity(),
12727            }),
12728            cx,
12729        );
12730    }
12731
12732    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12733        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12734        if let Some(item) = cx.read_from_clipboard() {
12735            let entries = item.entries();
12736
12737            match entries.first() {
12738                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12739                // of all the pasted entries.
12740                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12741                    .do_paste(
12742                        clipboard_string.text(),
12743                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12744                        true,
12745                        window,
12746                        cx,
12747                    ),
12748                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12749            }
12750        }
12751    }
12752
12753    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12754        if self.read_only(cx) {
12755            return;
12756        }
12757
12758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12759
12760        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12761            if let Some((selections, _)) =
12762                self.selection_history.transaction(transaction_id).cloned()
12763            {
12764                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12765                    s.select_anchors(selections.to_vec());
12766                });
12767            } else {
12768                log::error!(
12769                    "No entry in selection_history found for undo. \
12770                     This may correspond to a bug where undo does not update the selection. \
12771                     If this is occurring, please add details to \
12772                     https://github.com/zed-industries/zed/issues/22692"
12773                );
12774            }
12775            self.request_autoscroll(Autoscroll::fit(), cx);
12776            self.unmark_text(window, cx);
12777            self.refresh_edit_prediction(true, false, window, cx);
12778            cx.emit(EditorEvent::Edited { transaction_id });
12779            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12780        }
12781    }
12782
12783    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12784        if self.read_only(cx) {
12785            return;
12786        }
12787
12788        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12789
12790        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12791            if let Some((_, Some(selections))) =
12792                self.selection_history.transaction(transaction_id).cloned()
12793            {
12794                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12795                    s.select_anchors(selections.to_vec());
12796                });
12797            } else {
12798                log::error!(
12799                    "No entry in selection_history found for redo. \
12800                     This may correspond to a bug where undo does not update the selection. \
12801                     If this is occurring, please add details to \
12802                     https://github.com/zed-industries/zed/issues/22692"
12803                );
12804            }
12805            self.request_autoscroll(Autoscroll::fit(), cx);
12806            self.unmark_text(window, cx);
12807            self.refresh_edit_prediction(true, false, window, cx);
12808            cx.emit(EditorEvent::Edited { transaction_id });
12809        }
12810    }
12811
12812    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12813        self.buffer
12814            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12815    }
12816
12817    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12818        self.buffer
12819            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12820    }
12821
12822    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12823        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12824        self.change_selections(Default::default(), window, cx, |s| {
12825            s.move_with(|map, selection| {
12826                let cursor = if selection.is_empty() {
12827                    movement::left(map, selection.start)
12828                } else {
12829                    selection.start
12830                };
12831                selection.collapse_to(cursor, SelectionGoal::None);
12832            });
12833        })
12834    }
12835
12836    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12837        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12838        self.change_selections(Default::default(), window, cx, |s| {
12839            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12840        })
12841    }
12842
12843    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12844        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12845        self.change_selections(Default::default(), window, cx, |s| {
12846            s.move_with(|map, selection| {
12847                let cursor = if selection.is_empty() {
12848                    movement::right(map, selection.end)
12849                } else {
12850                    selection.end
12851                };
12852                selection.collapse_to(cursor, SelectionGoal::None)
12853            });
12854        })
12855    }
12856
12857    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12858        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12859        self.change_selections(Default::default(), window, cx, |s| {
12860            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12861        });
12862    }
12863
12864    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12865        if self.take_rename(true, window, cx).is_some() {
12866            return;
12867        }
12868
12869        if self.mode.is_single_line() {
12870            cx.propagate();
12871            return;
12872        }
12873
12874        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12875
12876        let text_layout_details = &self.text_layout_details(window);
12877        let selection_count = self.selections.count();
12878        let first_selection = self.selections.first_anchor();
12879
12880        self.change_selections(Default::default(), window, cx, |s| {
12881            s.move_with(|map, selection| {
12882                if !selection.is_empty() {
12883                    selection.goal = SelectionGoal::None;
12884                }
12885                let (cursor, goal) = movement::up(
12886                    map,
12887                    selection.start,
12888                    selection.goal,
12889                    false,
12890                    text_layout_details,
12891                );
12892                selection.collapse_to(cursor, goal);
12893            });
12894        });
12895
12896        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12897        {
12898            cx.propagate();
12899        }
12900    }
12901
12902    pub fn move_up_by_lines(
12903        &mut self,
12904        action: &MoveUpByLines,
12905        window: &mut Window,
12906        cx: &mut Context<Self>,
12907    ) {
12908        if self.take_rename(true, window, cx).is_some() {
12909            return;
12910        }
12911
12912        if self.mode.is_single_line() {
12913            cx.propagate();
12914            return;
12915        }
12916
12917        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12918
12919        let text_layout_details = &self.text_layout_details(window);
12920
12921        self.change_selections(Default::default(), window, cx, |s| {
12922            s.move_with(|map, selection| {
12923                if !selection.is_empty() {
12924                    selection.goal = SelectionGoal::None;
12925                }
12926                let (cursor, goal) = movement::up_by_rows(
12927                    map,
12928                    selection.start,
12929                    action.lines,
12930                    selection.goal,
12931                    false,
12932                    text_layout_details,
12933                );
12934                selection.collapse_to(cursor, goal);
12935            });
12936        })
12937    }
12938
12939    pub fn move_down_by_lines(
12940        &mut self,
12941        action: &MoveDownByLines,
12942        window: &mut Window,
12943        cx: &mut Context<Self>,
12944    ) {
12945        if self.take_rename(true, window, cx).is_some() {
12946            return;
12947        }
12948
12949        if self.mode.is_single_line() {
12950            cx.propagate();
12951            return;
12952        }
12953
12954        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12955
12956        let text_layout_details = &self.text_layout_details(window);
12957
12958        self.change_selections(Default::default(), window, cx, |s| {
12959            s.move_with(|map, selection| {
12960                if !selection.is_empty() {
12961                    selection.goal = SelectionGoal::None;
12962                }
12963                let (cursor, goal) = movement::down_by_rows(
12964                    map,
12965                    selection.start,
12966                    action.lines,
12967                    selection.goal,
12968                    false,
12969                    text_layout_details,
12970                );
12971                selection.collapse_to(cursor, goal);
12972            });
12973        })
12974    }
12975
12976    pub fn select_down_by_lines(
12977        &mut self,
12978        action: &SelectDownByLines,
12979        window: &mut Window,
12980        cx: &mut Context<Self>,
12981    ) {
12982        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12983        let text_layout_details = &self.text_layout_details(window);
12984        self.change_selections(Default::default(), window, cx, |s| {
12985            s.move_heads_with(|map, head, goal| {
12986                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12987            })
12988        })
12989    }
12990
12991    pub fn select_up_by_lines(
12992        &mut self,
12993        action: &SelectUpByLines,
12994        window: &mut Window,
12995        cx: &mut Context<Self>,
12996    ) {
12997        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12998        let text_layout_details = &self.text_layout_details(window);
12999        self.change_selections(Default::default(), window, cx, |s| {
13000            s.move_heads_with(|map, head, goal| {
13001                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13002            })
13003        })
13004    }
13005
13006    pub fn select_page_up(
13007        &mut self,
13008        _: &SelectPageUp,
13009        window: &mut Window,
13010        cx: &mut Context<Self>,
13011    ) {
13012        let Some(row_count) = self.visible_row_count() else {
13013            return;
13014        };
13015
13016        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13017
13018        let text_layout_details = &self.text_layout_details(window);
13019
13020        self.change_selections(Default::default(), window, cx, |s| {
13021            s.move_heads_with(|map, head, goal| {
13022                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13023            })
13024        })
13025    }
13026
13027    pub fn move_page_up(
13028        &mut self,
13029        action: &MovePageUp,
13030        window: &mut Window,
13031        cx: &mut Context<Self>,
13032    ) {
13033        if self.take_rename(true, window, cx).is_some() {
13034            return;
13035        }
13036
13037        if self
13038            .context_menu
13039            .borrow_mut()
13040            .as_mut()
13041            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13042            .unwrap_or(false)
13043        {
13044            return;
13045        }
13046
13047        if matches!(self.mode, EditorMode::SingleLine) {
13048            cx.propagate();
13049            return;
13050        }
13051
13052        let Some(row_count) = self.visible_row_count() else {
13053            return;
13054        };
13055
13056        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13057
13058        let effects = if action.center_cursor {
13059            SelectionEffects::scroll(Autoscroll::center())
13060        } else {
13061            SelectionEffects::default()
13062        };
13063
13064        let text_layout_details = &self.text_layout_details(window);
13065
13066        self.change_selections(effects, window, cx, |s| {
13067            s.move_with(|map, selection| {
13068                if !selection.is_empty() {
13069                    selection.goal = SelectionGoal::None;
13070                }
13071                let (cursor, goal) = movement::up_by_rows(
13072                    map,
13073                    selection.end,
13074                    row_count,
13075                    selection.goal,
13076                    false,
13077                    text_layout_details,
13078                );
13079                selection.collapse_to(cursor, goal);
13080            });
13081        });
13082    }
13083
13084    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13085        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13086        let text_layout_details = &self.text_layout_details(window);
13087        self.change_selections(Default::default(), window, cx, |s| {
13088            s.move_heads_with(|map, head, goal| {
13089                movement::up(map, head, goal, false, text_layout_details)
13090            })
13091        })
13092    }
13093
13094    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13095        self.take_rename(true, window, cx);
13096
13097        if self.mode.is_single_line() {
13098            cx.propagate();
13099            return;
13100        }
13101
13102        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13103
13104        let text_layout_details = &self.text_layout_details(window);
13105        let selection_count = self.selections.count();
13106        let first_selection = self.selections.first_anchor();
13107
13108        self.change_selections(Default::default(), window, cx, |s| {
13109            s.move_with(|map, selection| {
13110                if !selection.is_empty() {
13111                    selection.goal = SelectionGoal::None;
13112                }
13113                let (cursor, goal) = movement::down(
13114                    map,
13115                    selection.end,
13116                    selection.goal,
13117                    false,
13118                    text_layout_details,
13119                );
13120                selection.collapse_to(cursor, goal);
13121            });
13122        });
13123
13124        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13125        {
13126            cx.propagate();
13127        }
13128    }
13129
13130    pub fn select_page_down(
13131        &mut self,
13132        _: &SelectPageDown,
13133        window: &mut Window,
13134        cx: &mut Context<Self>,
13135    ) {
13136        let Some(row_count) = self.visible_row_count() else {
13137            return;
13138        };
13139
13140        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13141
13142        let text_layout_details = &self.text_layout_details(window);
13143
13144        self.change_selections(Default::default(), window, cx, |s| {
13145            s.move_heads_with(|map, head, goal| {
13146                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13147            })
13148        })
13149    }
13150
13151    pub fn move_page_down(
13152        &mut self,
13153        action: &MovePageDown,
13154        window: &mut Window,
13155        cx: &mut Context<Self>,
13156    ) {
13157        if self.take_rename(true, window, cx).is_some() {
13158            return;
13159        }
13160
13161        if self
13162            .context_menu
13163            .borrow_mut()
13164            .as_mut()
13165            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13166            .unwrap_or(false)
13167        {
13168            return;
13169        }
13170
13171        if matches!(self.mode, EditorMode::SingleLine) {
13172            cx.propagate();
13173            return;
13174        }
13175
13176        let Some(row_count) = self.visible_row_count() else {
13177            return;
13178        };
13179
13180        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13181
13182        let effects = if action.center_cursor {
13183            SelectionEffects::scroll(Autoscroll::center())
13184        } else {
13185            SelectionEffects::default()
13186        };
13187
13188        let text_layout_details = &self.text_layout_details(window);
13189        self.change_selections(effects, window, cx, |s| {
13190            s.move_with(|map, selection| {
13191                if !selection.is_empty() {
13192                    selection.goal = SelectionGoal::None;
13193                }
13194                let (cursor, goal) = movement::down_by_rows(
13195                    map,
13196                    selection.end,
13197                    row_count,
13198                    selection.goal,
13199                    false,
13200                    text_layout_details,
13201                );
13202                selection.collapse_to(cursor, goal);
13203            });
13204        });
13205    }
13206
13207    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13208        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13209        let text_layout_details = &self.text_layout_details(window);
13210        self.change_selections(Default::default(), window, cx, |s| {
13211            s.move_heads_with(|map, head, goal| {
13212                movement::down(map, head, goal, false, text_layout_details)
13213            })
13214        });
13215    }
13216
13217    pub fn context_menu_first(
13218        &mut self,
13219        _: &ContextMenuFirst,
13220        window: &mut Window,
13221        cx: &mut Context<Self>,
13222    ) {
13223        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13224            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13225        }
13226    }
13227
13228    pub fn context_menu_prev(
13229        &mut self,
13230        _: &ContextMenuPrevious,
13231        window: &mut Window,
13232        cx: &mut Context<Self>,
13233    ) {
13234        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13235            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13236        }
13237    }
13238
13239    pub fn context_menu_next(
13240        &mut self,
13241        _: &ContextMenuNext,
13242        window: &mut Window,
13243        cx: &mut Context<Self>,
13244    ) {
13245        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13246            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13247        }
13248    }
13249
13250    pub fn context_menu_last(
13251        &mut self,
13252        _: &ContextMenuLast,
13253        window: &mut Window,
13254        cx: &mut Context<Self>,
13255    ) {
13256        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13257            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13258        }
13259    }
13260
13261    pub fn signature_help_prev(
13262        &mut self,
13263        _: &SignatureHelpPrevious,
13264        _: &mut Window,
13265        cx: &mut Context<Self>,
13266    ) {
13267        if let Some(popover) = self.signature_help_state.popover_mut() {
13268            if popover.current_signature == 0 {
13269                popover.current_signature = popover.signatures.len() - 1;
13270            } else {
13271                popover.current_signature -= 1;
13272            }
13273            cx.notify();
13274        }
13275    }
13276
13277    pub fn signature_help_next(
13278        &mut self,
13279        _: &SignatureHelpNext,
13280        _: &mut Window,
13281        cx: &mut Context<Self>,
13282    ) {
13283        if let Some(popover) = self.signature_help_state.popover_mut() {
13284            if popover.current_signature + 1 == popover.signatures.len() {
13285                popover.current_signature = 0;
13286            } else {
13287                popover.current_signature += 1;
13288            }
13289            cx.notify();
13290        }
13291    }
13292
13293    pub fn move_to_previous_word_start(
13294        &mut self,
13295        _: &MoveToPreviousWordStart,
13296        window: &mut Window,
13297        cx: &mut Context<Self>,
13298    ) {
13299        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13300        self.change_selections(Default::default(), window, cx, |s| {
13301            s.move_cursors_with(|map, head, _| {
13302                (
13303                    movement::previous_word_start(map, head),
13304                    SelectionGoal::None,
13305                )
13306            });
13307        })
13308    }
13309
13310    pub fn move_to_previous_subword_start(
13311        &mut self,
13312        _: &MoveToPreviousSubwordStart,
13313        window: &mut Window,
13314        cx: &mut Context<Self>,
13315    ) {
13316        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13317        self.change_selections(Default::default(), window, cx, |s| {
13318            s.move_cursors_with(|map, head, _| {
13319                (
13320                    movement::previous_subword_start(map, head),
13321                    SelectionGoal::None,
13322                )
13323            });
13324        })
13325    }
13326
13327    pub fn select_to_previous_word_start(
13328        &mut self,
13329        _: &SelectToPreviousWordStart,
13330        window: &mut Window,
13331        cx: &mut Context<Self>,
13332    ) {
13333        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13334        self.change_selections(Default::default(), window, cx, |s| {
13335            s.move_heads_with(|map, head, _| {
13336                (
13337                    movement::previous_word_start(map, head),
13338                    SelectionGoal::None,
13339                )
13340            });
13341        })
13342    }
13343
13344    pub fn select_to_previous_subword_start(
13345        &mut self,
13346        _: &SelectToPreviousSubwordStart,
13347        window: &mut Window,
13348        cx: &mut Context<Self>,
13349    ) {
13350        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13351        self.change_selections(Default::default(), window, cx, |s| {
13352            s.move_heads_with(|map, head, _| {
13353                (
13354                    movement::previous_subword_start(map, head),
13355                    SelectionGoal::None,
13356                )
13357            });
13358        })
13359    }
13360
13361    pub fn delete_to_previous_word_start(
13362        &mut self,
13363        action: &DeleteToPreviousWordStart,
13364        window: &mut Window,
13365        cx: &mut Context<Self>,
13366    ) {
13367        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13368        self.transact(window, cx, |this, window, cx| {
13369            this.select_autoclose_pair(window, cx);
13370            this.change_selections(Default::default(), window, cx, |s| {
13371                s.move_with(|map, selection| {
13372                    if selection.is_empty() {
13373                        let mut cursor = if action.ignore_newlines {
13374                            movement::previous_word_start(map, selection.head())
13375                        } else {
13376                            movement::previous_word_start_or_newline(map, selection.head())
13377                        };
13378                        cursor = movement::adjust_greedy_deletion(
13379                            map,
13380                            selection.head(),
13381                            cursor,
13382                            action.ignore_brackets,
13383                        );
13384                        selection.set_head(cursor, SelectionGoal::None);
13385                    }
13386                });
13387            });
13388            this.insert("", window, cx);
13389        });
13390    }
13391
13392    pub fn delete_to_previous_subword_start(
13393        &mut self,
13394        _: &DeleteToPreviousSubwordStart,
13395        window: &mut Window,
13396        cx: &mut Context<Self>,
13397    ) {
13398        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13399        self.transact(window, cx, |this, window, cx| {
13400            this.select_autoclose_pair(window, cx);
13401            this.change_selections(Default::default(), window, cx, |s| {
13402                s.move_with(|map, selection| {
13403                    if selection.is_empty() {
13404                        let mut cursor = movement::previous_subword_start(map, selection.head());
13405                        cursor =
13406                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13407                        selection.set_head(cursor, SelectionGoal::None);
13408                    }
13409                });
13410            });
13411            this.insert("", window, cx);
13412        });
13413    }
13414
13415    pub fn move_to_next_word_end(
13416        &mut self,
13417        _: &MoveToNextWordEnd,
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_cursors_with(|map, head, _| {
13424                (movement::next_word_end(map, head), SelectionGoal::None)
13425            });
13426        })
13427    }
13428
13429    pub fn move_to_next_subword_end(
13430        &mut self,
13431        _: &MoveToNextSubwordEnd,
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_cursors_with(|map, head, _| {
13438                (movement::next_subword_end(map, head), SelectionGoal::None)
13439            });
13440        })
13441    }
13442
13443    pub fn select_to_next_word_end(
13444        &mut self,
13445        _: &SelectToNextWordEnd,
13446        window: &mut Window,
13447        cx: &mut Context<Self>,
13448    ) {
13449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13450        self.change_selections(Default::default(), window, cx, |s| {
13451            s.move_heads_with(|map, head, _| {
13452                (movement::next_word_end(map, head), SelectionGoal::None)
13453            });
13454        })
13455    }
13456
13457    pub fn select_to_next_subword_end(
13458        &mut self,
13459        _: &SelectToNextSubwordEnd,
13460        window: &mut Window,
13461        cx: &mut Context<Self>,
13462    ) {
13463        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13464        self.change_selections(Default::default(), window, cx, |s| {
13465            s.move_heads_with(|map, head, _| {
13466                (movement::next_subword_end(map, head), SelectionGoal::None)
13467            });
13468        })
13469    }
13470
13471    pub fn delete_to_next_word_end(
13472        &mut self,
13473        action: &DeleteToNextWordEnd,
13474        window: &mut Window,
13475        cx: &mut Context<Self>,
13476    ) {
13477        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13478        self.transact(window, cx, |this, window, cx| {
13479            this.change_selections(Default::default(), window, cx, |s| {
13480                s.move_with(|map, selection| {
13481                    if selection.is_empty() {
13482                        let mut cursor = if action.ignore_newlines {
13483                            movement::next_word_end(map, selection.head())
13484                        } else {
13485                            movement::next_word_end_or_newline(map, selection.head())
13486                        };
13487                        cursor = movement::adjust_greedy_deletion(
13488                            map,
13489                            selection.head(),
13490                            cursor,
13491                            action.ignore_brackets,
13492                        );
13493                        selection.set_head(cursor, SelectionGoal::None);
13494                    }
13495                });
13496            });
13497            this.insert("", window, cx);
13498        });
13499    }
13500
13501    pub fn delete_to_next_subword_end(
13502        &mut self,
13503        _: &DeleteToNextSubwordEnd,
13504        window: &mut Window,
13505        cx: &mut Context<Self>,
13506    ) {
13507        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13508        self.transact(window, cx, |this, window, cx| {
13509            this.change_selections(Default::default(), window, cx, |s| {
13510                s.move_with(|map, selection| {
13511                    if selection.is_empty() {
13512                        let mut cursor = movement::next_subword_end(map, selection.head());
13513                        cursor =
13514                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13515                        selection.set_head(cursor, SelectionGoal::None);
13516                    }
13517                });
13518            });
13519            this.insert("", window, cx);
13520        });
13521    }
13522
13523    pub fn move_to_beginning_of_line(
13524        &mut self,
13525        action: &MoveToBeginningOfLine,
13526        window: &mut Window,
13527        cx: &mut Context<Self>,
13528    ) {
13529        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13530        self.change_selections(Default::default(), window, cx, |s| {
13531            s.move_cursors_with(|map, head, _| {
13532                (
13533                    movement::indented_line_beginning(
13534                        map,
13535                        head,
13536                        action.stop_at_soft_wraps,
13537                        action.stop_at_indent,
13538                    ),
13539                    SelectionGoal::None,
13540                )
13541            });
13542        })
13543    }
13544
13545    pub fn select_to_beginning_of_line(
13546        &mut self,
13547        action: &SelectToBeginningOfLine,
13548        window: &mut Window,
13549        cx: &mut Context<Self>,
13550    ) {
13551        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13552        self.change_selections(Default::default(), window, cx, |s| {
13553            s.move_heads_with(|map, head, _| {
13554                (
13555                    movement::indented_line_beginning(
13556                        map,
13557                        head,
13558                        action.stop_at_soft_wraps,
13559                        action.stop_at_indent,
13560                    ),
13561                    SelectionGoal::None,
13562                )
13563            });
13564        });
13565    }
13566
13567    pub fn delete_to_beginning_of_line(
13568        &mut self,
13569        action: &DeleteToBeginningOfLine,
13570        window: &mut Window,
13571        cx: &mut Context<Self>,
13572    ) {
13573        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13574        self.transact(window, cx, |this, window, cx| {
13575            this.change_selections(Default::default(), window, cx, |s| {
13576                s.move_with(|_, selection| {
13577                    selection.reversed = true;
13578                });
13579            });
13580
13581            this.select_to_beginning_of_line(
13582                &SelectToBeginningOfLine {
13583                    stop_at_soft_wraps: false,
13584                    stop_at_indent: action.stop_at_indent,
13585                },
13586                window,
13587                cx,
13588            );
13589            this.backspace(&Backspace, window, cx);
13590        });
13591    }
13592
13593    pub fn move_to_end_of_line(
13594        &mut self,
13595        action: &MoveToEndOfLine,
13596        window: &mut Window,
13597        cx: &mut Context<Self>,
13598    ) {
13599        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13600        self.change_selections(Default::default(), window, cx, |s| {
13601            s.move_cursors_with(|map, head, _| {
13602                (
13603                    movement::line_end(map, head, action.stop_at_soft_wraps),
13604                    SelectionGoal::None,
13605                )
13606            });
13607        })
13608    }
13609
13610    pub fn select_to_end_of_line(
13611        &mut self,
13612        action: &SelectToEndOfLine,
13613        window: &mut Window,
13614        cx: &mut Context<Self>,
13615    ) {
13616        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13617        self.change_selections(Default::default(), window, cx, |s| {
13618            s.move_heads_with(|map, head, _| {
13619                (
13620                    movement::line_end(map, head, action.stop_at_soft_wraps),
13621                    SelectionGoal::None,
13622                )
13623            });
13624        })
13625    }
13626
13627    pub fn delete_to_end_of_line(
13628        &mut self,
13629        _: &DeleteToEndOfLine,
13630        window: &mut Window,
13631        cx: &mut Context<Self>,
13632    ) {
13633        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13634        self.transact(window, cx, |this, window, cx| {
13635            this.select_to_end_of_line(
13636                &SelectToEndOfLine {
13637                    stop_at_soft_wraps: false,
13638                },
13639                window,
13640                cx,
13641            );
13642            this.delete(&Delete, window, cx);
13643        });
13644    }
13645
13646    pub fn cut_to_end_of_line(
13647        &mut self,
13648        action: &CutToEndOfLine,
13649        window: &mut Window,
13650        cx: &mut Context<Self>,
13651    ) {
13652        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13653        self.transact(window, cx, |this, window, cx| {
13654            this.select_to_end_of_line(
13655                &SelectToEndOfLine {
13656                    stop_at_soft_wraps: false,
13657                },
13658                window,
13659                cx,
13660            );
13661            if !action.stop_at_newlines {
13662                this.change_selections(Default::default(), window, cx, |s| {
13663                    s.move_with(|_, sel| {
13664                        if sel.is_empty() {
13665                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13666                        }
13667                    });
13668                });
13669            }
13670            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13671            let item = this.cut_common(false, window, cx);
13672            cx.write_to_clipboard(item);
13673        });
13674    }
13675
13676    pub fn move_to_start_of_paragraph(
13677        &mut self,
13678        _: &MoveToStartOfParagraph,
13679        window: &mut Window,
13680        cx: &mut Context<Self>,
13681    ) {
13682        if matches!(self.mode, EditorMode::SingleLine) {
13683            cx.propagate();
13684            return;
13685        }
13686        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13687        self.change_selections(Default::default(), window, cx, |s| {
13688            s.move_with(|map, selection| {
13689                selection.collapse_to(
13690                    movement::start_of_paragraph(map, selection.head(), 1),
13691                    SelectionGoal::None,
13692                )
13693            });
13694        })
13695    }
13696
13697    pub fn move_to_end_of_paragraph(
13698        &mut self,
13699        _: &MoveToEndOfParagraph,
13700        window: &mut Window,
13701        cx: &mut Context<Self>,
13702    ) {
13703        if matches!(self.mode, EditorMode::SingleLine) {
13704            cx.propagate();
13705            return;
13706        }
13707        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13708        self.change_selections(Default::default(), window, cx, |s| {
13709            s.move_with(|map, selection| {
13710                selection.collapse_to(
13711                    movement::end_of_paragraph(map, selection.head(), 1),
13712                    SelectionGoal::None,
13713                )
13714            });
13715        })
13716    }
13717
13718    pub fn select_to_start_of_paragraph(
13719        &mut self,
13720        _: &SelectToStartOfParagraph,
13721        window: &mut Window,
13722        cx: &mut Context<Self>,
13723    ) {
13724        if matches!(self.mode, EditorMode::SingleLine) {
13725            cx.propagate();
13726            return;
13727        }
13728        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13729        self.change_selections(Default::default(), window, cx, |s| {
13730            s.move_heads_with(|map, head, _| {
13731                (
13732                    movement::start_of_paragraph(map, head, 1),
13733                    SelectionGoal::None,
13734                )
13735            });
13736        })
13737    }
13738
13739    pub fn select_to_end_of_paragraph(
13740        &mut self,
13741        _: &SelectToEndOfParagraph,
13742        window: &mut Window,
13743        cx: &mut Context<Self>,
13744    ) {
13745        if matches!(self.mode, EditorMode::SingleLine) {
13746            cx.propagate();
13747            return;
13748        }
13749        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13750        self.change_selections(Default::default(), window, cx, |s| {
13751            s.move_heads_with(|map, head, _| {
13752                (
13753                    movement::end_of_paragraph(map, head, 1),
13754                    SelectionGoal::None,
13755                )
13756            });
13757        })
13758    }
13759
13760    pub fn move_to_start_of_excerpt(
13761        &mut self,
13762        _: &MoveToStartOfExcerpt,
13763        window: &mut Window,
13764        cx: &mut Context<Self>,
13765    ) {
13766        if matches!(self.mode, EditorMode::SingleLine) {
13767            cx.propagate();
13768            return;
13769        }
13770        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13771        self.change_selections(Default::default(), window, cx, |s| {
13772            s.move_with(|map, selection| {
13773                selection.collapse_to(
13774                    movement::start_of_excerpt(
13775                        map,
13776                        selection.head(),
13777                        workspace::searchable::Direction::Prev,
13778                    ),
13779                    SelectionGoal::None,
13780                )
13781            });
13782        })
13783    }
13784
13785    pub fn move_to_start_of_next_excerpt(
13786        &mut self,
13787        _: &MoveToStartOfNextExcerpt,
13788        window: &mut Window,
13789        cx: &mut Context<Self>,
13790    ) {
13791        if matches!(self.mode, EditorMode::SingleLine) {
13792            cx.propagate();
13793            return;
13794        }
13795
13796        self.change_selections(Default::default(), window, cx, |s| {
13797            s.move_with(|map, selection| {
13798                selection.collapse_to(
13799                    movement::start_of_excerpt(
13800                        map,
13801                        selection.head(),
13802                        workspace::searchable::Direction::Next,
13803                    ),
13804                    SelectionGoal::None,
13805                )
13806            });
13807        })
13808    }
13809
13810    pub fn move_to_end_of_excerpt(
13811        &mut self,
13812        _: &MoveToEndOfExcerpt,
13813        window: &mut Window,
13814        cx: &mut Context<Self>,
13815    ) {
13816        if matches!(self.mode, EditorMode::SingleLine) {
13817            cx.propagate();
13818            return;
13819        }
13820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13821        self.change_selections(Default::default(), window, cx, |s| {
13822            s.move_with(|map, selection| {
13823                selection.collapse_to(
13824                    movement::end_of_excerpt(
13825                        map,
13826                        selection.head(),
13827                        workspace::searchable::Direction::Next,
13828                    ),
13829                    SelectionGoal::None,
13830                )
13831            });
13832        })
13833    }
13834
13835    pub fn move_to_end_of_previous_excerpt(
13836        &mut self,
13837        _: &MoveToEndOfPreviousExcerpt,
13838        window: &mut Window,
13839        cx: &mut Context<Self>,
13840    ) {
13841        if matches!(self.mode, EditorMode::SingleLine) {
13842            cx.propagate();
13843            return;
13844        }
13845        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13846        self.change_selections(Default::default(), window, cx, |s| {
13847            s.move_with(|map, selection| {
13848                selection.collapse_to(
13849                    movement::end_of_excerpt(
13850                        map,
13851                        selection.head(),
13852                        workspace::searchable::Direction::Prev,
13853                    ),
13854                    SelectionGoal::None,
13855                )
13856            });
13857        })
13858    }
13859
13860    pub fn select_to_start_of_excerpt(
13861        &mut self,
13862        _: &SelectToStartOfExcerpt,
13863        window: &mut Window,
13864        cx: &mut Context<Self>,
13865    ) {
13866        if matches!(self.mode, EditorMode::SingleLine) {
13867            cx.propagate();
13868            return;
13869        }
13870        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13871        self.change_selections(Default::default(), window, cx, |s| {
13872            s.move_heads_with(|map, head, _| {
13873                (
13874                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13875                    SelectionGoal::None,
13876                )
13877            });
13878        })
13879    }
13880
13881    pub fn select_to_start_of_next_excerpt(
13882        &mut self,
13883        _: &SelectToStartOfNextExcerpt,
13884        window: &mut Window,
13885        cx: &mut Context<Self>,
13886    ) {
13887        if matches!(self.mode, EditorMode::SingleLine) {
13888            cx.propagate();
13889            return;
13890        }
13891        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13892        self.change_selections(Default::default(), window, cx, |s| {
13893            s.move_heads_with(|map, head, _| {
13894                (
13895                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13896                    SelectionGoal::None,
13897                )
13898            });
13899        })
13900    }
13901
13902    pub fn select_to_end_of_excerpt(
13903        &mut self,
13904        _: &SelectToEndOfExcerpt,
13905        window: &mut Window,
13906        cx: &mut Context<Self>,
13907    ) {
13908        if matches!(self.mode, EditorMode::SingleLine) {
13909            cx.propagate();
13910            return;
13911        }
13912        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13913        self.change_selections(Default::default(), window, cx, |s| {
13914            s.move_heads_with(|map, head, _| {
13915                (
13916                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13917                    SelectionGoal::None,
13918                )
13919            });
13920        })
13921    }
13922
13923    pub fn select_to_end_of_previous_excerpt(
13924        &mut self,
13925        _: &SelectToEndOfPreviousExcerpt,
13926        window: &mut Window,
13927        cx: &mut Context<Self>,
13928    ) {
13929        if matches!(self.mode, EditorMode::SingleLine) {
13930            cx.propagate();
13931            return;
13932        }
13933        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13934        self.change_selections(Default::default(), window, cx, |s| {
13935            s.move_heads_with(|map, head, _| {
13936                (
13937                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13938                    SelectionGoal::None,
13939                )
13940            });
13941        })
13942    }
13943
13944    pub fn move_to_beginning(
13945        &mut self,
13946        _: &MoveToBeginning,
13947        window: &mut Window,
13948        cx: &mut Context<Self>,
13949    ) {
13950        if matches!(self.mode, EditorMode::SingleLine) {
13951            cx.propagate();
13952            return;
13953        }
13954        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13955        self.change_selections(Default::default(), window, cx, |s| {
13956            s.select_ranges(vec![0..0]);
13957        });
13958    }
13959
13960    pub fn select_to_beginning(
13961        &mut self,
13962        _: &SelectToBeginning,
13963        window: &mut Window,
13964        cx: &mut Context<Self>,
13965    ) {
13966        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
13967        selection.set_head(Point::zero(), SelectionGoal::None);
13968        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13969        self.change_selections(Default::default(), window, cx, |s| {
13970            s.select(vec![selection]);
13971        });
13972    }
13973
13974    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13975        if matches!(self.mode, EditorMode::SingleLine) {
13976            cx.propagate();
13977            return;
13978        }
13979        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13980        let cursor = self.buffer.read(cx).read(cx).len();
13981        self.change_selections(Default::default(), window, cx, |s| {
13982            s.select_ranges(vec![cursor..cursor])
13983        });
13984    }
13985
13986    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13987        self.nav_history = nav_history;
13988    }
13989
13990    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13991        self.nav_history.as_ref()
13992    }
13993
13994    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13995        self.push_to_nav_history(
13996            self.selections.newest_anchor().head(),
13997            None,
13998            false,
13999            true,
14000            cx,
14001        );
14002    }
14003
14004    fn push_to_nav_history(
14005        &mut self,
14006        cursor_anchor: Anchor,
14007        new_position: Option<Point>,
14008        is_deactivate: bool,
14009        always: bool,
14010        cx: &mut Context<Self>,
14011    ) {
14012        if let Some(nav_history) = self.nav_history.as_mut() {
14013            let buffer = self.buffer.read(cx).read(cx);
14014            let cursor_position = cursor_anchor.to_point(&buffer);
14015            let scroll_state = self.scroll_manager.anchor();
14016            let scroll_top_row = scroll_state.top_row(&buffer);
14017            drop(buffer);
14018
14019            if let Some(new_position) = new_position {
14020                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14021                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14022                    return;
14023                }
14024            }
14025
14026            nav_history.push(
14027                Some(NavigationData {
14028                    cursor_anchor,
14029                    cursor_position,
14030                    scroll_anchor: scroll_state,
14031                    scroll_top_row,
14032                }),
14033                cx,
14034            );
14035            cx.emit(EditorEvent::PushedToNavHistory {
14036                anchor: cursor_anchor,
14037                is_deactivate,
14038            })
14039        }
14040    }
14041
14042    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14044        let buffer = self.buffer.read(cx).snapshot(cx);
14045        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14046        selection.set_head(buffer.len(), SelectionGoal::None);
14047        self.change_selections(Default::default(), window, cx, |s| {
14048            s.select(vec![selection]);
14049        });
14050    }
14051
14052    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14053        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14054        let end = self.buffer.read(cx).read(cx).len();
14055        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14056            s.select_ranges(vec![0..end]);
14057        });
14058    }
14059
14060    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14061        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14062        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14063        let mut selections = self.selections.all::<Point>(&display_map);
14064        let max_point = display_map.buffer_snapshot().max_point();
14065        for selection in &mut selections {
14066            let rows = selection.spanned_rows(true, &display_map);
14067            selection.start = Point::new(rows.start.0, 0);
14068            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14069            selection.reversed = false;
14070        }
14071        self.change_selections(Default::default(), window, cx, |s| {
14072            s.select(selections);
14073        });
14074    }
14075
14076    pub fn split_selection_into_lines(
14077        &mut self,
14078        action: &SplitSelectionIntoLines,
14079        window: &mut Window,
14080        cx: &mut Context<Self>,
14081    ) {
14082        let selections = self
14083            .selections
14084            .all::<Point>(&self.display_snapshot(cx))
14085            .into_iter()
14086            .map(|selection| selection.start..selection.end)
14087            .collect::<Vec<_>>();
14088        self.unfold_ranges(&selections, true, true, cx);
14089
14090        let mut new_selection_ranges = Vec::new();
14091        {
14092            let buffer = self.buffer.read(cx).read(cx);
14093            for selection in selections {
14094                for row in selection.start.row..selection.end.row {
14095                    let line_start = Point::new(row, 0);
14096                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14097
14098                    if action.keep_selections {
14099                        // Keep the selection range for each line
14100                        let selection_start = if row == selection.start.row {
14101                            selection.start
14102                        } else {
14103                            line_start
14104                        };
14105                        new_selection_ranges.push(selection_start..line_end);
14106                    } else {
14107                        // Collapse to cursor at end of line
14108                        new_selection_ranges.push(line_end..line_end);
14109                    }
14110                }
14111
14112                let is_multiline_selection = selection.start.row != selection.end.row;
14113                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14114                // so this action feels more ergonomic when paired with other selection operations
14115                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14116                if !should_skip_last {
14117                    if action.keep_selections {
14118                        if is_multiline_selection {
14119                            let line_start = Point::new(selection.end.row, 0);
14120                            new_selection_ranges.push(line_start..selection.end);
14121                        } else {
14122                            new_selection_ranges.push(selection.start..selection.end);
14123                        }
14124                    } else {
14125                        new_selection_ranges.push(selection.end..selection.end);
14126                    }
14127                }
14128            }
14129        }
14130        self.change_selections(Default::default(), window, cx, |s| {
14131            s.select_ranges(new_selection_ranges);
14132        });
14133    }
14134
14135    pub fn add_selection_above(
14136        &mut self,
14137        action: &AddSelectionAbove,
14138        window: &mut Window,
14139        cx: &mut Context<Self>,
14140    ) {
14141        self.add_selection(true, action.skip_soft_wrap, window, cx);
14142    }
14143
14144    pub fn add_selection_below(
14145        &mut self,
14146        action: &AddSelectionBelow,
14147        window: &mut Window,
14148        cx: &mut Context<Self>,
14149    ) {
14150        self.add_selection(false, action.skip_soft_wrap, window, cx);
14151    }
14152
14153    fn add_selection(
14154        &mut self,
14155        above: bool,
14156        skip_soft_wrap: bool,
14157        window: &mut Window,
14158        cx: &mut Context<Self>,
14159    ) {
14160        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14161
14162        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14163        let all_selections = self.selections.all::<Point>(&display_map);
14164        let text_layout_details = self.text_layout_details(window);
14165
14166        let (mut columnar_selections, new_selections_to_columnarize) = {
14167            if let Some(state) = self.add_selections_state.as_ref() {
14168                let columnar_selection_ids: HashSet<_> = state
14169                    .groups
14170                    .iter()
14171                    .flat_map(|group| group.stack.iter())
14172                    .copied()
14173                    .collect();
14174
14175                all_selections
14176                    .into_iter()
14177                    .partition(|s| columnar_selection_ids.contains(&s.id))
14178            } else {
14179                (Vec::new(), all_selections)
14180            }
14181        };
14182
14183        let mut state = self
14184            .add_selections_state
14185            .take()
14186            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14187
14188        for selection in new_selections_to_columnarize {
14189            let range = selection.display_range(&display_map).sorted();
14190            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14191            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14192            let positions = start_x.min(end_x)..start_x.max(end_x);
14193            let mut stack = Vec::new();
14194            for row in range.start.row().0..=range.end.row().0 {
14195                if let Some(selection) = self.selections.build_columnar_selection(
14196                    &display_map,
14197                    DisplayRow(row),
14198                    &positions,
14199                    selection.reversed,
14200                    &text_layout_details,
14201                ) {
14202                    stack.push(selection.id);
14203                    columnar_selections.push(selection);
14204                }
14205            }
14206            if !stack.is_empty() {
14207                if above {
14208                    stack.reverse();
14209                }
14210                state.groups.push(AddSelectionsGroup { above, stack });
14211            }
14212        }
14213
14214        let mut final_selections = Vec::new();
14215        let end_row = if above {
14216            DisplayRow(0)
14217        } else {
14218            display_map.max_point().row()
14219        };
14220
14221        let mut last_added_item_per_group = HashMap::default();
14222        for group in state.groups.iter_mut() {
14223            if let Some(last_id) = group.stack.last() {
14224                last_added_item_per_group.insert(*last_id, group);
14225            }
14226        }
14227
14228        for selection in columnar_selections {
14229            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14230                if above == group.above {
14231                    let range = selection.display_range(&display_map).sorted();
14232                    debug_assert_eq!(range.start.row(), range.end.row());
14233                    let mut row = range.start.row();
14234                    let positions =
14235                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14236                            Pixels::from(start)..Pixels::from(end)
14237                        } else {
14238                            let start_x =
14239                                display_map.x_for_display_point(range.start, &text_layout_details);
14240                            let end_x =
14241                                display_map.x_for_display_point(range.end, &text_layout_details);
14242                            start_x.min(end_x)..start_x.max(end_x)
14243                        };
14244
14245                    let mut maybe_new_selection = None;
14246                    let direction = if above { -1 } else { 1 };
14247
14248                    while row != end_row {
14249                        if skip_soft_wrap {
14250                            row = display_map
14251                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14252                                .row();
14253                        } else if above {
14254                            row.0 -= 1;
14255                        } else {
14256                            row.0 += 1;
14257                        }
14258
14259                        if let Some(new_selection) = self.selections.build_columnar_selection(
14260                            &display_map,
14261                            row,
14262                            &positions,
14263                            selection.reversed,
14264                            &text_layout_details,
14265                        ) {
14266                            maybe_new_selection = Some(new_selection);
14267                            break;
14268                        }
14269                    }
14270
14271                    if let Some(new_selection) = maybe_new_selection {
14272                        group.stack.push(new_selection.id);
14273                        if above {
14274                            final_selections.push(new_selection);
14275                            final_selections.push(selection);
14276                        } else {
14277                            final_selections.push(selection);
14278                            final_selections.push(new_selection);
14279                        }
14280                    } else {
14281                        final_selections.push(selection);
14282                    }
14283                } else {
14284                    group.stack.pop();
14285                }
14286            } else {
14287                final_selections.push(selection);
14288            }
14289        }
14290
14291        self.change_selections(Default::default(), window, cx, |s| {
14292            s.select(final_selections);
14293        });
14294
14295        let final_selection_ids: HashSet<_> = self
14296            .selections
14297            .all::<Point>(&display_map)
14298            .iter()
14299            .map(|s| s.id)
14300            .collect();
14301        state.groups.retain_mut(|group| {
14302            // selections might get merged above so we remove invalid items from stacks
14303            group.stack.retain(|id| final_selection_ids.contains(id));
14304
14305            // single selection in stack can be treated as initial state
14306            group.stack.len() > 1
14307        });
14308
14309        if !state.groups.is_empty() {
14310            self.add_selections_state = Some(state);
14311        }
14312    }
14313
14314    fn select_match_ranges(
14315        &mut self,
14316        range: Range<usize>,
14317        reversed: bool,
14318        replace_newest: bool,
14319        auto_scroll: Option<Autoscroll>,
14320        window: &mut Window,
14321        cx: &mut Context<Editor>,
14322    ) {
14323        self.unfold_ranges(
14324            std::slice::from_ref(&range),
14325            false,
14326            auto_scroll.is_some(),
14327            cx,
14328        );
14329        let effects = if let Some(scroll) = auto_scroll {
14330            SelectionEffects::scroll(scroll)
14331        } else {
14332            SelectionEffects::no_scroll()
14333        };
14334        self.change_selections(effects, window, cx, |s| {
14335            if replace_newest {
14336                s.delete(s.newest_anchor().id);
14337            }
14338            if reversed {
14339                s.insert_range(range.end..range.start);
14340            } else {
14341                s.insert_range(range);
14342            }
14343        });
14344    }
14345
14346    pub fn select_next_match_internal(
14347        &mut self,
14348        display_map: &DisplaySnapshot,
14349        replace_newest: bool,
14350        autoscroll: Option<Autoscroll>,
14351        window: &mut Window,
14352        cx: &mut Context<Self>,
14353    ) -> Result<()> {
14354        let buffer = display_map.buffer_snapshot();
14355        let mut selections = self.selections.all::<usize>(&display_map);
14356        if let Some(mut select_next_state) = self.select_next_state.take() {
14357            let query = &select_next_state.query;
14358            if !select_next_state.done {
14359                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14360                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14361                let mut next_selected_range = None;
14362
14363                let bytes_after_last_selection =
14364                    buffer.bytes_in_range(last_selection.end..buffer.len());
14365                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14366                let query_matches = query
14367                    .stream_find_iter(bytes_after_last_selection)
14368                    .map(|result| (last_selection.end, result))
14369                    .chain(
14370                        query
14371                            .stream_find_iter(bytes_before_first_selection)
14372                            .map(|result| (0, result)),
14373                    );
14374
14375                for (start_offset, query_match) in query_matches {
14376                    let query_match = query_match.unwrap(); // can only fail due to I/O
14377                    let offset_range =
14378                        start_offset + query_match.start()..start_offset + query_match.end();
14379
14380                    if !select_next_state.wordwise
14381                        || (!buffer.is_inside_word(offset_range.start, None)
14382                            && !buffer.is_inside_word(offset_range.end, None))
14383                    {
14384                        let idx = selections
14385                            .partition_point(|selection| selection.end <= offset_range.start);
14386                        let overlaps = selections
14387                            .get(idx)
14388                            .map_or(false, |selection| selection.start < offset_range.end);
14389
14390                        if !overlaps {
14391                            next_selected_range = Some(offset_range);
14392                            break;
14393                        }
14394                    }
14395                }
14396
14397                if let Some(next_selected_range) = next_selected_range {
14398                    self.select_match_ranges(
14399                        next_selected_range,
14400                        last_selection.reversed,
14401                        replace_newest,
14402                        autoscroll,
14403                        window,
14404                        cx,
14405                    );
14406                } else {
14407                    select_next_state.done = true;
14408                }
14409            }
14410
14411            self.select_next_state = Some(select_next_state);
14412        } else {
14413            let mut only_carets = true;
14414            let mut same_text_selected = true;
14415            let mut selected_text = None;
14416
14417            let mut selections_iter = selections.iter().peekable();
14418            while let Some(selection) = selections_iter.next() {
14419                if selection.start != selection.end {
14420                    only_carets = false;
14421                }
14422
14423                if same_text_selected {
14424                    if selected_text.is_none() {
14425                        selected_text =
14426                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14427                    }
14428
14429                    if let Some(next_selection) = selections_iter.peek() {
14430                        if next_selection.range().len() == selection.range().len() {
14431                            let next_selected_text = buffer
14432                                .text_for_range(next_selection.range())
14433                                .collect::<String>();
14434                            if Some(next_selected_text) != selected_text {
14435                                same_text_selected = false;
14436                                selected_text = None;
14437                            }
14438                        } else {
14439                            same_text_selected = false;
14440                            selected_text = None;
14441                        }
14442                    }
14443                }
14444            }
14445
14446            if only_carets {
14447                for selection in &mut selections {
14448                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14449                    selection.start = word_range.start;
14450                    selection.end = word_range.end;
14451                    selection.goal = SelectionGoal::None;
14452                    selection.reversed = false;
14453                    self.select_match_ranges(
14454                        selection.start..selection.end,
14455                        selection.reversed,
14456                        replace_newest,
14457                        autoscroll,
14458                        window,
14459                        cx,
14460                    );
14461                }
14462
14463                if selections.len() == 1 {
14464                    let selection = selections
14465                        .last()
14466                        .expect("ensured that there's only one selection");
14467                    let query = buffer
14468                        .text_for_range(selection.start..selection.end)
14469                        .collect::<String>();
14470                    let is_empty = query.is_empty();
14471                    let select_state = SelectNextState {
14472                        query: AhoCorasick::new(&[query])?,
14473                        wordwise: true,
14474                        done: is_empty,
14475                    };
14476                    self.select_next_state = Some(select_state);
14477                } else {
14478                    self.select_next_state = None;
14479                }
14480            } else if let Some(selected_text) = selected_text {
14481                self.select_next_state = Some(SelectNextState {
14482                    query: AhoCorasick::new(&[selected_text])?,
14483                    wordwise: false,
14484                    done: false,
14485                });
14486                self.select_next_match_internal(
14487                    display_map,
14488                    replace_newest,
14489                    autoscroll,
14490                    window,
14491                    cx,
14492                )?;
14493            }
14494        }
14495        Ok(())
14496    }
14497
14498    pub fn select_all_matches(
14499        &mut self,
14500        _action: &SelectAllMatches,
14501        window: &mut Window,
14502        cx: &mut Context<Self>,
14503    ) -> Result<()> {
14504        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14505
14506        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14507
14508        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14509        let Some(select_next_state) = self.select_next_state.as_mut() else {
14510            return Ok(());
14511        };
14512        if select_next_state.done {
14513            return Ok(());
14514        }
14515
14516        let mut new_selections = Vec::new();
14517
14518        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14519        let buffer = display_map.buffer_snapshot();
14520        let query_matches = select_next_state
14521            .query
14522            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14523
14524        for query_match in query_matches.into_iter() {
14525            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14526            let offset_range = if reversed {
14527                query_match.end()..query_match.start()
14528            } else {
14529                query_match.start()..query_match.end()
14530            };
14531
14532            if !select_next_state.wordwise
14533                || (!buffer.is_inside_word(offset_range.start, None)
14534                    && !buffer.is_inside_word(offset_range.end, None))
14535            {
14536                new_selections.push(offset_range.start..offset_range.end);
14537            }
14538        }
14539
14540        select_next_state.done = true;
14541
14542        if new_selections.is_empty() {
14543            log::error!("bug: new_selections is empty in select_all_matches");
14544            return Ok(());
14545        }
14546
14547        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14548        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14549            selections.select_ranges(new_selections)
14550        });
14551
14552        Ok(())
14553    }
14554
14555    pub fn select_next(
14556        &mut self,
14557        action: &SelectNext,
14558        window: &mut Window,
14559        cx: &mut Context<Self>,
14560    ) -> Result<()> {
14561        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14562        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14563        self.select_next_match_internal(
14564            &display_map,
14565            action.replace_newest,
14566            Some(Autoscroll::newest()),
14567            window,
14568            cx,
14569        )?;
14570        Ok(())
14571    }
14572
14573    pub fn select_previous(
14574        &mut self,
14575        action: &SelectPrevious,
14576        window: &mut Window,
14577        cx: &mut Context<Self>,
14578    ) -> Result<()> {
14579        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14580        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14581        let buffer = display_map.buffer_snapshot();
14582        let mut selections = self.selections.all::<usize>(&display_map);
14583        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14584            let query = &select_prev_state.query;
14585            if !select_prev_state.done {
14586                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14587                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14588                let mut next_selected_range = None;
14589                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14590                let bytes_before_last_selection =
14591                    buffer.reversed_bytes_in_range(0..last_selection.start);
14592                let bytes_after_first_selection =
14593                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14594                let query_matches = query
14595                    .stream_find_iter(bytes_before_last_selection)
14596                    .map(|result| (last_selection.start, result))
14597                    .chain(
14598                        query
14599                            .stream_find_iter(bytes_after_first_selection)
14600                            .map(|result| (buffer.len(), result)),
14601                    );
14602                for (end_offset, query_match) in query_matches {
14603                    let query_match = query_match.unwrap(); // can only fail due to I/O
14604                    let offset_range =
14605                        end_offset - query_match.end()..end_offset - query_match.start();
14606
14607                    if !select_prev_state.wordwise
14608                        || (!buffer.is_inside_word(offset_range.start, None)
14609                            && !buffer.is_inside_word(offset_range.end, None))
14610                    {
14611                        next_selected_range = Some(offset_range);
14612                        break;
14613                    }
14614                }
14615
14616                if let Some(next_selected_range) = next_selected_range {
14617                    self.select_match_ranges(
14618                        next_selected_range,
14619                        last_selection.reversed,
14620                        action.replace_newest,
14621                        Some(Autoscroll::newest()),
14622                        window,
14623                        cx,
14624                    );
14625                } else {
14626                    select_prev_state.done = true;
14627                }
14628            }
14629
14630            self.select_prev_state = Some(select_prev_state);
14631        } else {
14632            let mut only_carets = true;
14633            let mut same_text_selected = true;
14634            let mut selected_text = None;
14635
14636            let mut selections_iter = selections.iter().peekable();
14637            while let Some(selection) = selections_iter.next() {
14638                if selection.start != selection.end {
14639                    only_carets = false;
14640                }
14641
14642                if same_text_selected {
14643                    if selected_text.is_none() {
14644                        selected_text =
14645                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14646                    }
14647
14648                    if let Some(next_selection) = selections_iter.peek() {
14649                        if next_selection.range().len() == selection.range().len() {
14650                            let next_selected_text = buffer
14651                                .text_for_range(next_selection.range())
14652                                .collect::<String>();
14653                            if Some(next_selected_text) != selected_text {
14654                                same_text_selected = false;
14655                                selected_text = None;
14656                            }
14657                        } else {
14658                            same_text_selected = false;
14659                            selected_text = None;
14660                        }
14661                    }
14662                }
14663            }
14664
14665            if only_carets {
14666                for selection in &mut selections {
14667                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14668                    selection.start = word_range.start;
14669                    selection.end = word_range.end;
14670                    selection.goal = SelectionGoal::None;
14671                    selection.reversed = false;
14672                    self.select_match_ranges(
14673                        selection.start..selection.end,
14674                        selection.reversed,
14675                        action.replace_newest,
14676                        Some(Autoscroll::newest()),
14677                        window,
14678                        cx,
14679                    );
14680                }
14681                if selections.len() == 1 {
14682                    let selection = selections
14683                        .last()
14684                        .expect("ensured that there's only one selection");
14685                    let query = buffer
14686                        .text_for_range(selection.start..selection.end)
14687                        .collect::<String>();
14688                    let is_empty = query.is_empty();
14689                    let select_state = SelectNextState {
14690                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14691                        wordwise: true,
14692                        done: is_empty,
14693                    };
14694                    self.select_prev_state = Some(select_state);
14695                } else {
14696                    self.select_prev_state = None;
14697                }
14698            } else if let Some(selected_text) = selected_text {
14699                self.select_prev_state = Some(SelectNextState {
14700                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14701                    wordwise: false,
14702                    done: false,
14703                });
14704                self.select_previous(action, window, cx)?;
14705            }
14706        }
14707        Ok(())
14708    }
14709
14710    pub fn find_next_match(
14711        &mut self,
14712        _: &FindNextMatch,
14713        window: &mut Window,
14714        cx: &mut Context<Self>,
14715    ) -> Result<()> {
14716        let selections = self.selections.disjoint_anchors_arc();
14717        match selections.first() {
14718            Some(first) if selections.len() >= 2 => {
14719                self.change_selections(Default::default(), window, cx, |s| {
14720                    s.select_ranges([first.range()]);
14721                });
14722            }
14723            _ => self.select_next(
14724                &SelectNext {
14725                    replace_newest: true,
14726                },
14727                window,
14728                cx,
14729            )?,
14730        }
14731        Ok(())
14732    }
14733
14734    pub fn find_previous_match(
14735        &mut self,
14736        _: &FindPreviousMatch,
14737        window: &mut Window,
14738        cx: &mut Context<Self>,
14739    ) -> Result<()> {
14740        let selections = self.selections.disjoint_anchors_arc();
14741        match selections.last() {
14742            Some(last) if selections.len() >= 2 => {
14743                self.change_selections(Default::default(), window, cx, |s| {
14744                    s.select_ranges([last.range()]);
14745                });
14746            }
14747            _ => self.select_previous(
14748                &SelectPrevious {
14749                    replace_newest: true,
14750                },
14751                window,
14752                cx,
14753            )?,
14754        }
14755        Ok(())
14756    }
14757
14758    pub fn toggle_comments(
14759        &mut self,
14760        action: &ToggleComments,
14761        window: &mut Window,
14762        cx: &mut Context<Self>,
14763    ) {
14764        if self.read_only(cx) {
14765            return;
14766        }
14767        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14768        let text_layout_details = &self.text_layout_details(window);
14769        self.transact(window, cx, |this, window, cx| {
14770            let mut selections = this
14771                .selections
14772                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14773            let mut edits = Vec::new();
14774            let mut selection_edit_ranges = Vec::new();
14775            let mut last_toggled_row = None;
14776            let snapshot = this.buffer.read(cx).read(cx);
14777            let empty_str: Arc<str> = Arc::default();
14778            let mut suffixes_inserted = Vec::new();
14779            let ignore_indent = action.ignore_indent;
14780
14781            fn comment_prefix_range(
14782                snapshot: &MultiBufferSnapshot,
14783                row: MultiBufferRow,
14784                comment_prefix: &str,
14785                comment_prefix_whitespace: &str,
14786                ignore_indent: bool,
14787            ) -> Range<Point> {
14788                let indent_size = if ignore_indent {
14789                    0
14790                } else {
14791                    snapshot.indent_size_for_line(row).len
14792                };
14793
14794                let start = Point::new(row.0, indent_size);
14795
14796                let mut line_bytes = snapshot
14797                    .bytes_in_range(start..snapshot.max_point())
14798                    .flatten()
14799                    .copied();
14800
14801                // If this line currently begins with the line comment prefix, then record
14802                // the range containing the prefix.
14803                if line_bytes
14804                    .by_ref()
14805                    .take(comment_prefix.len())
14806                    .eq(comment_prefix.bytes())
14807                {
14808                    // Include any whitespace that matches the comment prefix.
14809                    let matching_whitespace_len = line_bytes
14810                        .zip(comment_prefix_whitespace.bytes())
14811                        .take_while(|(a, b)| a == b)
14812                        .count() as u32;
14813                    let end = Point::new(
14814                        start.row,
14815                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14816                    );
14817                    start..end
14818                } else {
14819                    start..start
14820                }
14821            }
14822
14823            fn comment_suffix_range(
14824                snapshot: &MultiBufferSnapshot,
14825                row: MultiBufferRow,
14826                comment_suffix: &str,
14827                comment_suffix_has_leading_space: bool,
14828            ) -> Range<Point> {
14829                let end = Point::new(row.0, snapshot.line_len(row));
14830                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14831
14832                let mut line_end_bytes = snapshot
14833                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14834                    .flatten()
14835                    .copied();
14836
14837                let leading_space_len = if suffix_start_column > 0
14838                    && line_end_bytes.next() == Some(b' ')
14839                    && comment_suffix_has_leading_space
14840                {
14841                    1
14842                } else {
14843                    0
14844                };
14845
14846                // If this line currently begins with the line comment prefix, then record
14847                // the range containing the prefix.
14848                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14849                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14850                    start..end
14851                } else {
14852                    end..end
14853                }
14854            }
14855
14856            // TODO: Handle selections that cross excerpts
14857            for selection in &mut selections {
14858                let start_column = snapshot
14859                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14860                    .len;
14861                let language = if let Some(language) =
14862                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14863                {
14864                    language
14865                } else {
14866                    continue;
14867                };
14868
14869                selection_edit_ranges.clear();
14870
14871                // If multiple selections contain a given row, avoid processing that
14872                // row more than once.
14873                let mut start_row = MultiBufferRow(selection.start.row);
14874                if last_toggled_row == Some(start_row) {
14875                    start_row = start_row.next_row();
14876                }
14877                let end_row =
14878                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14879                        MultiBufferRow(selection.end.row - 1)
14880                    } else {
14881                        MultiBufferRow(selection.end.row)
14882                    };
14883                last_toggled_row = Some(end_row);
14884
14885                if start_row > end_row {
14886                    continue;
14887                }
14888
14889                // If the language has line comments, toggle those.
14890                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14891
14892                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14893                if ignore_indent {
14894                    full_comment_prefixes = full_comment_prefixes
14895                        .into_iter()
14896                        .map(|s| Arc::from(s.trim_end()))
14897                        .collect();
14898                }
14899
14900                if !full_comment_prefixes.is_empty() {
14901                    let first_prefix = full_comment_prefixes
14902                        .first()
14903                        .expect("prefixes is non-empty");
14904                    let prefix_trimmed_lengths = full_comment_prefixes
14905                        .iter()
14906                        .map(|p| p.trim_end_matches(' ').len())
14907                        .collect::<SmallVec<[usize; 4]>>();
14908
14909                    let mut all_selection_lines_are_comments = true;
14910
14911                    for row in start_row.0..=end_row.0 {
14912                        let row = MultiBufferRow(row);
14913                        if start_row < end_row && snapshot.is_line_blank(row) {
14914                            continue;
14915                        }
14916
14917                        let prefix_range = full_comment_prefixes
14918                            .iter()
14919                            .zip(prefix_trimmed_lengths.iter().copied())
14920                            .map(|(prefix, trimmed_prefix_len)| {
14921                                comment_prefix_range(
14922                                    snapshot.deref(),
14923                                    row,
14924                                    &prefix[..trimmed_prefix_len],
14925                                    &prefix[trimmed_prefix_len..],
14926                                    ignore_indent,
14927                                )
14928                            })
14929                            .max_by_key(|range| range.end.column - range.start.column)
14930                            .expect("prefixes is non-empty");
14931
14932                        if prefix_range.is_empty() {
14933                            all_selection_lines_are_comments = false;
14934                        }
14935
14936                        selection_edit_ranges.push(prefix_range);
14937                    }
14938
14939                    if all_selection_lines_are_comments {
14940                        edits.extend(
14941                            selection_edit_ranges
14942                                .iter()
14943                                .cloned()
14944                                .map(|range| (range, empty_str.clone())),
14945                        );
14946                    } else {
14947                        let min_column = selection_edit_ranges
14948                            .iter()
14949                            .map(|range| range.start.column)
14950                            .min()
14951                            .unwrap_or(0);
14952                        edits.extend(selection_edit_ranges.iter().map(|range| {
14953                            let position = Point::new(range.start.row, min_column);
14954                            (position..position, first_prefix.clone())
14955                        }));
14956                    }
14957                } else if let Some(BlockCommentConfig {
14958                    start: full_comment_prefix,
14959                    end: comment_suffix,
14960                    ..
14961                }) = language.block_comment()
14962                {
14963                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14964                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14965                    let prefix_range = comment_prefix_range(
14966                        snapshot.deref(),
14967                        start_row,
14968                        comment_prefix,
14969                        comment_prefix_whitespace,
14970                        ignore_indent,
14971                    );
14972                    let suffix_range = comment_suffix_range(
14973                        snapshot.deref(),
14974                        end_row,
14975                        comment_suffix.trim_start_matches(' '),
14976                        comment_suffix.starts_with(' '),
14977                    );
14978
14979                    if prefix_range.is_empty() || suffix_range.is_empty() {
14980                        edits.push((
14981                            prefix_range.start..prefix_range.start,
14982                            full_comment_prefix.clone(),
14983                        ));
14984                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14985                        suffixes_inserted.push((end_row, comment_suffix.len()));
14986                    } else {
14987                        edits.push((prefix_range, empty_str.clone()));
14988                        edits.push((suffix_range, empty_str.clone()));
14989                    }
14990                } else {
14991                    continue;
14992                }
14993            }
14994
14995            drop(snapshot);
14996            this.buffer.update(cx, |buffer, cx| {
14997                buffer.edit(edits, None, cx);
14998            });
14999
15000            // Adjust selections so that they end before any comment suffixes that
15001            // were inserted.
15002            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15003            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15004            let snapshot = this.buffer.read(cx).read(cx);
15005            for selection in &mut selections {
15006                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15007                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15008                        Ordering::Less => {
15009                            suffixes_inserted.next();
15010                            continue;
15011                        }
15012                        Ordering::Greater => break,
15013                        Ordering::Equal => {
15014                            if selection.end.column == snapshot.line_len(row) {
15015                                if selection.is_empty() {
15016                                    selection.start.column -= suffix_len as u32;
15017                                }
15018                                selection.end.column -= suffix_len as u32;
15019                            }
15020                            break;
15021                        }
15022                    }
15023                }
15024            }
15025
15026            drop(snapshot);
15027            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15028
15029            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15030            let selections_on_single_row = selections.windows(2).all(|selections| {
15031                selections[0].start.row == selections[1].start.row
15032                    && selections[0].end.row == selections[1].end.row
15033                    && selections[0].start.row == selections[0].end.row
15034            });
15035            let selections_selecting = selections
15036                .iter()
15037                .any(|selection| selection.start != selection.end);
15038            let advance_downwards = action.advance_downwards
15039                && selections_on_single_row
15040                && !selections_selecting
15041                && !matches!(this.mode, EditorMode::SingleLine);
15042
15043            if advance_downwards {
15044                let snapshot = this.buffer.read(cx).snapshot(cx);
15045
15046                this.change_selections(Default::default(), window, cx, |s| {
15047                    s.move_cursors_with(|display_snapshot, display_point, _| {
15048                        let mut point = display_point.to_point(display_snapshot);
15049                        point.row += 1;
15050                        point = snapshot.clip_point(point, Bias::Left);
15051                        let display_point = point.to_display_point(display_snapshot);
15052                        let goal = SelectionGoal::HorizontalPosition(
15053                            display_snapshot
15054                                .x_for_display_point(display_point, text_layout_details)
15055                                .into(),
15056                        );
15057                        (display_point, goal)
15058                    })
15059                });
15060            }
15061        });
15062    }
15063
15064    pub fn select_enclosing_symbol(
15065        &mut self,
15066        _: &SelectEnclosingSymbol,
15067        window: &mut Window,
15068        cx: &mut Context<Self>,
15069    ) {
15070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15071
15072        let buffer = self.buffer.read(cx).snapshot(cx);
15073        let old_selections = self
15074            .selections
15075            .all::<usize>(&self.display_snapshot(cx))
15076            .into_boxed_slice();
15077
15078        fn update_selection(
15079            selection: &Selection<usize>,
15080            buffer_snap: &MultiBufferSnapshot,
15081        ) -> Option<Selection<usize>> {
15082            let cursor = selection.head();
15083            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15084            for symbol in symbols.iter().rev() {
15085                let start = symbol.range.start.to_offset(buffer_snap);
15086                let end = symbol.range.end.to_offset(buffer_snap);
15087                let new_range = start..end;
15088                if start < selection.start || end > selection.end {
15089                    return Some(Selection {
15090                        id: selection.id,
15091                        start: new_range.start,
15092                        end: new_range.end,
15093                        goal: SelectionGoal::None,
15094                        reversed: selection.reversed,
15095                    });
15096                }
15097            }
15098            None
15099        }
15100
15101        let mut selected_larger_symbol = false;
15102        let new_selections = old_selections
15103            .iter()
15104            .map(|selection| match update_selection(selection, &buffer) {
15105                Some(new_selection) => {
15106                    if new_selection.range() != selection.range() {
15107                        selected_larger_symbol = true;
15108                    }
15109                    new_selection
15110                }
15111                None => selection.clone(),
15112            })
15113            .collect::<Vec<_>>();
15114
15115        if selected_larger_symbol {
15116            self.change_selections(Default::default(), window, cx, |s| {
15117                s.select(new_selections);
15118            });
15119        }
15120    }
15121
15122    pub fn select_larger_syntax_node(
15123        &mut self,
15124        _: &SelectLargerSyntaxNode,
15125        window: &mut Window,
15126        cx: &mut Context<Self>,
15127    ) {
15128        let Some(visible_row_count) = self.visible_row_count() else {
15129            return;
15130        };
15131        let old_selections: Box<[_]> = self
15132            .selections
15133            .all::<usize>(&self.display_snapshot(cx))
15134            .into();
15135        if old_selections.is_empty() {
15136            return;
15137        }
15138
15139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15140
15141        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15142        let buffer = self.buffer.read(cx).snapshot(cx);
15143
15144        let mut selected_larger_node = false;
15145        let mut new_selections = old_selections
15146            .iter()
15147            .map(|selection| {
15148                let old_range = selection.start..selection.end;
15149
15150                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15151                    // manually select word at selection
15152                    if ["string_content", "inline"].contains(&node.kind()) {
15153                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15154                        // ignore if word is already selected
15155                        if !word_range.is_empty() && old_range != word_range {
15156                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15157                            // only select word if start and end point belongs to same word
15158                            if word_range == last_word_range {
15159                                selected_larger_node = true;
15160                                return Selection {
15161                                    id: selection.id,
15162                                    start: word_range.start,
15163                                    end: word_range.end,
15164                                    goal: SelectionGoal::None,
15165                                    reversed: selection.reversed,
15166                                };
15167                            }
15168                        }
15169                    }
15170                }
15171
15172                let mut new_range = old_range.clone();
15173                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15174                    new_range = range;
15175                    if !node.is_named() {
15176                        continue;
15177                    }
15178                    if !display_map.intersects_fold(new_range.start)
15179                        && !display_map.intersects_fold(new_range.end)
15180                    {
15181                        break;
15182                    }
15183                }
15184
15185                selected_larger_node |= new_range != old_range;
15186                Selection {
15187                    id: selection.id,
15188                    start: new_range.start,
15189                    end: new_range.end,
15190                    goal: SelectionGoal::None,
15191                    reversed: selection.reversed,
15192                }
15193            })
15194            .collect::<Vec<_>>();
15195
15196        if !selected_larger_node {
15197            return; // don't put this call in the history
15198        }
15199
15200        // scroll based on transformation done to the last selection created by the user
15201        let (last_old, last_new) = old_selections
15202            .last()
15203            .zip(new_selections.last().cloned())
15204            .expect("old_selections isn't empty");
15205
15206        // revert selection
15207        let is_selection_reversed = {
15208            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15209            new_selections.last_mut().expect("checked above").reversed =
15210                should_newest_selection_be_reversed;
15211            should_newest_selection_be_reversed
15212        };
15213
15214        if selected_larger_node {
15215            self.select_syntax_node_history.disable_clearing = true;
15216            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15217                s.select(new_selections.clone());
15218            });
15219            self.select_syntax_node_history.disable_clearing = false;
15220        }
15221
15222        let start_row = last_new.start.to_display_point(&display_map).row().0;
15223        let end_row = last_new.end.to_display_point(&display_map).row().0;
15224        let selection_height = end_row - start_row + 1;
15225        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15226
15227        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15228        let scroll_behavior = if fits_on_the_screen {
15229            self.request_autoscroll(Autoscroll::fit(), cx);
15230            SelectSyntaxNodeScrollBehavior::FitSelection
15231        } else if is_selection_reversed {
15232            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15233            SelectSyntaxNodeScrollBehavior::CursorTop
15234        } else {
15235            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15236            SelectSyntaxNodeScrollBehavior::CursorBottom
15237        };
15238
15239        self.select_syntax_node_history.push((
15240            old_selections,
15241            scroll_behavior,
15242            is_selection_reversed,
15243        ));
15244    }
15245
15246    pub fn select_smaller_syntax_node(
15247        &mut self,
15248        _: &SelectSmallerSyntaxNode,
15249        window: &mut Window,
15250        cx: &mut Context<Self>,
15251    ) {
15252        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15253
15254        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15255            self.select_syntax_node_history.pop()
15256        {
15257            if let Some(selection) = selections.last_mut() {
15258                selection.reversed = is_selection_reversed;
15259            }
15260
15261            self.select_syntax_node_history.disable_clearing = true;
15262            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15263                s.select(selections.to_vec());
15264            });
15265            self.select_syntax_node_history.disable_clearing = false;
15266
15267            match scroll_behavior {
15268                SelectSyntaxNodeScrollBehavior::CursorTop => {
15269                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15270                }
15271                SelectSyntaxNodeScrollBehavior::FitSelection => {
15272                    self.request_autoscroll(Autoscroll::fit(), cx);
15273                }
15274                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15275                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15276                }
15277            }
15278        }
15279    }
15280
15281    pub fn unwrap_syntax_node(
15282        &mut self,
15283        _: &UnwrapSyntaxNode,
15284        window: &mut Window,
15285        cx: &mut Context<Self>,
15286    ) {
15287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15288
15289        let buffer = self.buffer.read(cx).snapshot(cx);
15290        let selections = self
15291            .selections
15292            .all::<usize>(&self.display_snapshot(cx))
15293            .into_iter()
15294            // subtracting the offset requires sorting
15295            .sorted_by_key(|i| i.start);
15296
15297        let full_edits = selections
15298            .into_iter()
15299            .filter_map(|selection| {
15300                let child = if selection.is_empty()
15301                    && let Some((_, ancestor_range)) =
15302                        buffer.syntax_ancestor(selection.start..selection.end)
15303                {
15304                    ancestor_range
15305                } else {
15306                    selection.range()
15307                };
15308
15309                let mut parent = child.clone();
15310                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15311                    parent = ancestor_range;
15312                    if parent.start < child.start || parent.end > child.end {
15313                        break;
15314                    }
15315                }
15316
15317                if parent == child {
15318                    return None;
15319                }
15320                let text = buffer.text_for_range(child).collect::<String>();
15321                Some((selection.id, parent, text))
15322            })
15323            .collect::<Vec<_>>();
15324        if full_edits.is_empty() {
15325            return;
15326        }
15327
15328        self.transact(window, cx, |this, window, cx| {
15329            this.buffer.update(cx, |buffer, cx| {
15330                buffer.edit(
15331                    full_edits
15332                        .iter()
15333                        .map(|(_, p, t)| (p.clone(), t.clone()))
15334                        .collect::<Vec<_>>(),
15335                    None,
15336                    cx,
15337                );
15338            });
15339            this.change_selections(Default::default(), window, cx, |s| {
15340                let mut offset = 0;
15341                let mut selections = vec![];
15342                for (id, parent, text) in full_edits {
15343                    let start = parent.start - offset;
15344                    offset += parent.len() - text.len();
15345                    selections.push(Selection {
15346                        id,
15347                        start,
15348                        end: start + text.len(),
15349                        reversed: false,
15350                        goal: Default::default(),
15351                    });
15352                }
15353                s.select(selections);
15354            });
15355        });
15356    }
15357
15358    pub fn select_next_syntax_node(
15359        &mut self,
15360        _: &SelectNextSyntaxNode,
15361        window: &mut Window,
15362        cx: &mut Context<Self>,
15363    ) {
15364        let old_selections: Box<[_]> = self
15365            .selections
15366            .all::<usize>(&self.display_snapshot(cx))
15367            .into();
15368        if old_selections.is_empty() {
15369            return;
15370        }
15371
15372        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15373
15374        let buffer = self.buffer.read(cx).snapshot(cx);
15375        let mut selected_sibling = false;
15376
15377        let new_selections = old_selections
15378            .iter()
15379            .map(|selection| {
15380                let old_range = selection.start..selection.end;
15381
15382                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15383                    let new_range = node.byte_range();
15384                    selected_sibling = true;
15385                    Selection {
15386                        id: selection.id,
15387                        start: new_range.start,
15388                        end: new_range.end,
15389                        goal: SelectionGoal::None,
15390                        reversed: selection.reversed,
15391                    }
15392                } else {
15393                    selection.clone()
15394                }
15395            })
15396            .collect::<Vec<_>>();
15397
15398        if selected_sibling {
15399            self.change_selections(
15400                SelectionEffects::scroll(Autoscroll::fit()),
15401                window,
15402                cx,
15403                |s| {
15404                    s.select(new_selections);
15405                },
15406            );
15407        }
15408    }
15409
15410    pub fn select_prev_syntax_node(
15411        &mut self,
15412        _: &SelectPreviousSyntaxNode,
15413        window: &mut Window,
15414        cx: &mut Context<Self>,
15415    ) {
15416        let old_selections: Box<[_]> = self
15417            .selections
15418            .all::<usize>(&self.display_snapshot(cx))
15419            .into();
15420        if old_selections.is_empty() {
15421            return;
15422        }
15423
15424        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15425
15426        let buffer = self.buffer.read(cx).snapshot(cx);
15427        let mut selected_sibling = false;
15428
15429        let new_selections = old_selections
15430            .iter()
15431            .map(|selection| {
15432                let old_range = selection.start..selection.end;
15433
15434                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15435                    let new_range = node.byte_range();
15436                    selected_sibling = true;
15437                    Selection {
15438                        id: selection.id,
15439                        start: new_range.start,
15440                        end: new_range.end,
15441                        goal: SelectionGoal::None,
15442                        reversed: selection.reversed,
15443                    }
15444                } else {
15445                    selection.clone()
15446                }
15447            })
15448            .collect::<Vec<_>>();
15449
15450        if selected_sibling {
15451            self.change_selections(
15452                SelectionEffects::scroll(Autoscroll::fit()),
15453                window,
15454                cx,
15455                |s| {
15456                    s.select(new_selections);
15457                },
15458            );
15459        }
15460    }
15461
15462    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15463        if !EditorSettings::get_global(cx).gutter.runnables {
15464            self.clear_tasks();
15465            return Task::ready(());
15466        }
15467        let project = self.project().map(Entity::downgrade);
15468        let task_sources = self.lsp_task_sources(cx);
15469        let multi_buffer = self.buffer.downgrade();
15470        cx.spawn_in(window, async move |editor, cx| {
15471            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15472            let Some(project) = project.and_then(|p| p.upgrade()) else {
15473                return;
15474            };
15475            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15476                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15477            }) else {
15478                return;
15479            };
15480
15481            let hide_runnables = project
15482                .update(cx, |project, _| project.is_via_collab())
15483                .unwrap_or(true);
15484            if hide_runnables {
15485                return;
15486            }
15487            let new_rows =
15488                cx.background_spawn({
15489                    let snapshot = display_snapshot.clone();
15490                    async move {
15491                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15492                    }
15493                })
15494                    .await;
15495            let Ok(lsp_tasks) =
15496                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15497            else {
15498                return;
15499            };
15500            let lsp_tasks = lsp_tasks.await;
15501
15502            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15503                lsp_tasks
15504                    .into_iter()
15505                    .flat_map(|(kind, tasks)| {
15506                        tasks.into_iter().filter_map(move |(location, task)| {
15507                            Some((kind.clone(), location?, task))
15508                        })
15509                    })
15510                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15511                        let buffer = location.target.buffer;
15512                        let buffer_snapshot = buffer.read(cx).snapshot();
15513                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15514                            |(excerpt_id, snapshot, _)| {
15515                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15516                                    display_snapshot
15517                                        .buffer_snapshot()
15518                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15519                                } else {
15520                                    None
15521                                }
15522                            },
15523                        );
15524                        if let Some(offset) = offset {
15525                            let task_buffer_range =
15526                                location.target.range.to_point(&buffer_snapshot);
15527                            let context_buffer_range =
15528                                task_buffer_range.to_offset(&buffer_snapshot);
15529                            let context_range = BufferOffset(context_buffer_range.start)
15530                                ..BufferOffset(context_buffer_range.end);
15531
15532                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15533                                .or_insert_with(|| RunnableTasks {
15534                                    templates: Vec::new(),
15535                                    offset,
15536                                    column: task_buffer_range.start.column,
15537                                    extra_variables: HashMap::default(),
15538                                    context_range,
15539                                })
15540                                .templates
15541                                .push((kind, task.original_task().clone()));
15542                        }
15543
15544                        acc
15545                    })
15546            }) else {
15547                return;
15548            };
15549
15550            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15551                buffer.language_settings(cx).tasks.prefer_lsp
15552            }) else {
15553                return;
15554            };
15555
15556            let rows = Self::runnable_rows(
15557                project,
15558                display_snapshot,
15559                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15560                new_rows,
15561                cx.clone(),
15562            )
15563            .await;
15564            editor
15565                .update(cx, |editor, _| {
15566                    editor.clear_tasks();
15567                    for (key, mut value) in rows {
15568                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15569                            value.templates.extend(lsp_tasks.templates);
15570                        }
15571
15572                        editor.insert_tasks(key, value);
15573                    }
15574                    for (key, value) in lsp_tasks_by_rows {
15575                        editor.insert_tasks(key, value);
15576                    }
15577                })
15578                .ok();
15579        })
15580    }
15581    fn fetch_runnable_ranges(
15582        snapshot: &DisplaySnapshot,
15583        range: Range<Anchor>,
15584    ) -> Vec<language::RunnableRange> {
15585        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15586    }
15587
15588    fn runnable_rows(
15589        project: Entity<Project>,
15590        snapshot: DisplaySnapshot,
15591        prefer_lsp: bool,
15592        runnable_ranges: Vec<RunnableRange>,
15593        cx: AsyncWindowContext,
15594    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15595        cx.spawn(async move |cx| {
15596            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15597            for mut runnable in runnable_ranges {
15598                let Some(tasks) = cx
15599                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15600                    .ok()
15601                else {
15602                    continue;
15603                };
15604                let mut tasks = tasks.await;
15605
15606                if prefer_lsp {
15607                    tasks.retain(|(task_kind, _)| {
15608                        !matches!(task_kind, TaskSourceKind::Language { .. })
15609                    });
15610                }
15611                if tasks.is_empty() {
15612                    continue;
15613                }
15614
15615                let point = runnable
15616                    .run_range
15617                    .start
15618                    .to_point(&snapshot.buffer_snapshot());
15619                let Some(row) = snapshot
15620                    .buffer_snapshot()
15621                    .buffer_line_for_row(MultiBufferRow(point.row))
15622                    .map(|(_, range)| range.start.row)
15623                else {
15624                    continue;
15625                };
15626
15627                let context_range =
15628                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15629                runnable_rows.push((
15630                    (runnable.buffer_id, row),
15631                    RunnableTasks {
15632                        templates: tasks,
15633                        offset: snapshot
15634                            .buffer_snapshot()
15635                            .anchor_before(runnable.run_range.start),
15636                        context_range,
15637                        column: point.column,
15638                        extra_variables: runnable.extra_captures,
15639                    },
15640                ));
15641            }
15642            runnable_rows
15643        })
15644    }
15645
15646    fn templates_with_tags(
15647        project: &Entity<Project>,
15648        runnable: &mut Runnable,
15649        cx: &mut App,
15650    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15651        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15652            let (worktree_id, file) = project
15653                .buffer_for_id(runnable.buffer, cx)
15654                .and_then(|buffer| buffer.read(cx).file())
15655                .map(|file| (file.worktree_id(cx), file.clone()))
15656                .unzip();
15657
15658            (
15659                project.task_store().read(cx).task_inventory().cloned(),
15660                worktree_id,
15661                file,
15662            )
15663        });
15664
15665        let tags = mem::take(&mut runnable.tags);
15666        let language = runnable.language.clone();
15667        cx.spawn(async move |cx| {
15668            let mut templates_with_tags = Vec::new();
15669            if let Some(inventory) = inventory {
15670                for RunnableTag(tag) in tags {
15671                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15672                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15673                    }) else {
15674                        return templates_with_tags;
15675                    };
15676                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15677                        move |(_, template)| {
15678                            template.tags.iter().any(|source_tag| source_tag == &tag)
15679                        },
15680                    ));
15681                }
15682            }
15683            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15684
15685            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15686                // Strongest source wins; if we have worktree tag binding, prefer that to
15687                // global and language bindings;
15688                // if we have a global binding, prefer that to language binding.
15689                let first_mismatch = templates_with_tags
15690                    .iter()
15691                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15692                if let Some(index) = first_mismatch {
15693                    templates_with_tags.truncate(index);
15694                }
15695            }
15696
15697            templates_with_tags
15698        })
15699    }
15700
15701    pub fn move_to_enclosing_bracket(
15702        &mut self,
15703        _: &MoveToEnclosingBracket,
15704        window: &mut Window,
15705        cx: &mut Context<Self>,
15706    ) {
15707        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15708        self.change_selections(Default::default(), window, cx, |s| {
15709            s.move_offsets_with(|snapshot, selection| {
15710                let Some(enclosing_bracket_ranges) =
15711                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15712                else {
15713                    return;
15714                };
15715
15716                let mut best_length = usize::MAX;
15717                let mut best_inside = false;
15718                let mut best_in_bracket_range = false;
15719                let mut best_destination = None;
15720                for (open, close) in enclosing_bracket_ranges {
15721                    let close = close.to_inclusive();
15722                    let length = close.end() - open.start;
15723                    let inside = selection.start >= open.end && selection.end <= *close.start();
15724                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15725                        || close.contains(&selection.head());
15726
15727                    // If best is next to a bracket and current isn't, skip
15728                    if !in_bracket_range && best_in_bracket_range {
15729                        continue;
15730                    }
15731
15732                    // Prefer smaller lengths unless best is inside and current isn't
15733                    if length > best_length && (best_inside || !inside) {
15734                        continue;
15735                    }
15736
15737                    best_length = length;
15738                    best_inside = inside;
15739                    best_in_bracket_range = in_bracket_range;
15740                    best_destination = Some(
15741                        if close.contains(&selection.start) && close.contains(&selection.end) {
15742                            if inside { open.end } else { open.start }
15743                        } else if inside {
15744                            *close.start()
15745                        } else {
15746                            *close.end()
15747                        },
15748                    );
15749                }
15750
15751                if let Some(destination) = best_destination {
15752                    selection.collapse_to(destination, SelectionGoal::None);
15753                }
15754            })
15755        });
15756    }
15757
15758    pub fn undo_selection(
15759        &mut self,
15760        _: &UndoSelection,
15761        window: &mut Window,
15762        cx: &mut Context<Self>,
15763    ) {
15764        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15765        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15766            self.selection_history.mode = SelectionHistoryMode::Undoing;
15767            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15768                this.end_selection(window, cx);
15769                this.change_selections(
15770                    SelectionEffects::scroll(Autoscroll::newest()),
15771                    window,
15772                    cx,
15773                    |s| s.select_anchors(entry.selections.to_vec()),
15774                );
15775            });
15776            self.selection_history.mode = SelectionHistoryMode::Normal;
15777
15778            self.select_next_state = entry.select_next_state;
15779            self.select_prev_state = entry.select_prev_state;
15780            self.add_selections_state = entry.add_selections_state;
15781        }
15782    }
15783
15784    pub fn redo_selection(
15785        &mut self,
15786        _: &RedoSelection,
15787        window: &mut Window,
15788        cx: &mut Context<Self>,
15789    ) {
15790        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15791        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15792            self.selection_history.mode = SelectionHistoryMode::Redoing;
15793            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15794                this.end_selection(window, cx);
15795                this.change_selections(
15796                    SelectionEffects::scroll(Autoscroll::newest()),
15797                    window,
15798                    cx,
15799                    |s| s.select_anchors(entry.selections.to_vec()),
15800                );
15801            });
15802            self.selection_history.mode = SelectionHistoryMode::Normal;
15803
15804            self.select_next_state = entry.select_next_state;
15805            self.select_prev_state = entry.select_prev_state;
15806            self.add_selections_state = entry.add_selections_state;
15807        }
15808    }
15809
15810    pub fn expand_excerpts(
15811        &mut self,
15812        action: &ExpandExcerpts,
15813        _: &mut Window,
15814        cx: &mut Context<Self>,
15815    ) {
15816        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15817    }
15818
15819    pub fn expand_excerpts_down(
15820        &mut self,
15821        action: &ExpandExcerptsDown,
15822        _: &mut Window,
15823        cx: &mut Context<Self>,
15824    ) {
15825        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15826    }
15827
15828    pub fn expand_excerpts_up(
15829        &mut self,
15830        action: &ExpandExcerptsUp,
15831        _: &mut Window,
15832        cx: &mut Context<Self>,
15833    ) {
15834        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15835    }
15836
15837    pub fn expand_excerpts_for_direction(
15838        &mut self,
15839        lines: u32,
15840        direction: ExpandExcerptDirection,
15841
15842        cx: &mut Context<Self>,
15843    ) {
15844        let selections = self.selections.disjoint_anchors_arc();
15845
15846        let lines = if lines == 0 {
15847            EditorSettings::get_global(cx).expand_excerpt_lines
15848        } else {
15849            lines
15850        };
15851
15852        self.buffer.update(cx, |buffer, cx| {
15853            let snapshot = buffer.snapshot(cx);
15854            let mut excerpt_ids = selections
15855                .iter()
15856                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15857                .collect::<Vec<_>>();
15858            excerpt_ids.sort();
15859            excerpt_ids.dedup();
15860            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15861        })
15862    }
15863
15864    pub fn expand_excerpt(
15865        &mut self,
15866        excerpt: ExcerptId,
15867        direction: ExpandExcerptDirection,
15868        window: &mut Window,
15869        cx: &mut Context<Self>,
15870    ) {
15871        let current_scroll_position = self.scroll_position(cx);
15872        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15873        let mut scroll = None;
15874
15875        if direction == ExpandExcerptDirection::Down {
15876            let multi_buffer = self.buffer.read(cx);
15877            let snapshot = multi_buffer.snapshot(cx);
15878            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15879                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15880                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15881            {
15882                let buffer_snapshot = buffer.read(cx).snapshot();
15883                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15884                let last_row = buffer_snapshot.max_point().row;
15885                let lines_below = last_row.saturating_sub(excerpt_end_row);
15886                if lines_below >= lines_to_expand {
15887                    scroll = Some(
15888                        current_scroll_position
15889                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
15890                    );
15891                }
15892            }
15893        }
15894        if direction == ExpandExcerptDirection::Up
15895            && self
15896                .buffer
15897                .read(cx)
15898                .snapshot(cx)
15899                .excerpt_before(excerpt)
15900                .is_none()
15901        {
15902            scroll = Some(current_scroll_position);
15903        }
15904
15905        self.buffer.update(cx, |buffer, cx| {
15906            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15907        });
15908
15909        if let Some(new_scroll_position) = scroll {
15910            self.set_scroll_position(new_scroll_position, window, cx);
15911        }
15912    }
15913
15914    pub fn go_to_singleton_buffer_point(
15915        &mut self,
15916        point: Point,
15917        window: &mut Window,
15918        cx: &mut Context<Self>,
15919    ) {
15920        self.go_to_singleton_buffer_range(point..point, window, cx);
15921    }
15922
15923    pub fn go_to_singleton_buffer_range(
15924        &mut self,
15925        range: Range<Point>,
15926        window: &mut Window,
15927        cx: &mut Context<Self>,
15928    ) {
15929        let multibuffer = self.buffer().read(cx);
15930        let Some(buffer) = multibuffer.as_singleton() else {
15931            return;
15932        };
15933        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15934            return;
15935        };
15936        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15937            return;
15938        };
15939        self.change_selections(
15940            SelectionEffects::default().nav_history(true),
15941            window,
15942            cx,
15943            |s| s.select_anchor_ranges([start..end]),
15944        );
15945    }
15946
15947    pub fn go_to_diagnostic(
15948        &mut self,
15949        action: &GoToDiagnostic,
15950        window: &mut Window,
15951        cx: &mut Context<Self>,
15952    ) {
15953        if !self.diagnostics_enabled() {
15954            return;
15955        }
15956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15957        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15958    }
15959
15960    pub fn go_to_prev_diagnostic(
15961        &mut self,
15962        action: &GoToPreviousDiagnostic,
15963        window: &mut Window,
15964        cx: &mut Context<Self>,
15965    ) {
15966        if !self.diagnostics_enabled() {
15967            return;
15968        }
15969        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15970        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15971    }
15972
15973    pub fn go_to_diagnostic_impl(
15974        &mut self,
15975        direction: Direction,
15976        severity: GoToDiagnosticSeverityFilter,
15977        window: &mut Window,
15978        cx: &mut Context<Self>,
15979    ) {
15980        let buffer = self.buffer.read(cx).snapshot(cx);
15981        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
15982
15983        let mut active_group_id = None;
15984        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15985            && active_group.active_range.start.to_offset(&buffer) == selection.start
15986        {
15987            active_group_id = Some(active_group.group_id);
15988        }
15989
15990        fn filtered<'a>(
15991            severity: GoToDiagnosticSeverityFilter,
15992            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
15993        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
15994            diagnostics
15995                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15996                .filter(|entry| entry.range.start != entry.range.end)
15997                .filter(|entry| !entry.diagnostic.is_unnecessary)
15998        }
15999
16000        let before = filtered(
16001            severity,
16002            buffer
16003                .diagnostics_in_range(0..selection.start)
16004                .filter(|entry| entry.range.start <= selection.start),
16005        );
16006        let after = filtered(
16007            severity,
16008            buffer
16009                .diagnostics_in_range(selection.start..buffer.len())
16010                .filter(|entry| entry.range.start >= selection.start),
16011        );
16012
16013        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16014        if direction == Direction::Prev {
16015            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16016            {
16017                for diagnostic in prev_diagnostics.into_iter().rev() {
16018                    if diagnostic.range.start != selection.start
16019                        || active_group_id
16020                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16021                    {
16022                        found = Some(diagnostic);
16023                        break 'outer;
16024                    }
16025                }
16026            }
16027        } else {
16028            for diagnostic in after.chain(before) {
16029                if diagnostic.range.start != selection.start
16030                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16031                {
16032                    found = Some(diagnostic);
16033                    break;
16034                }
16035            }
16036        }
16037        let Some(next_diagnostic) = found else {
16038            return;
16039        };
16040
16041        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16042        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16043            return;
16044        };
16045        let snapshot = self.snapshot(window, cx);
16046        if snapshot.intersects_fold(next_diagnostic.range.start) {
16047            self.unfold_ranges(
16048                std::slice::from_ref(&next_diagnostic.range),
16049                true,
16050                false,
16051                cx,
16052            );
16053        }
16054        self.change_selections(Default::default(), window, cx, |s| {
16055            s.select_ranges(vec![
16056                next_diagnostic.range.start..next_diagnostic.range.start,
16057            ])
16058        });
16059        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16060        self.refresh_edit_prediction(false, true, window, cx);
16061    }
16062
16063    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16064        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16065        let snapshot = self.snapshot(window, cx);
16066        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16067        self.go_to_hunk_before_or_after_position(
16068            &snapshot,
16069            selection.head(),
16070            Direction::Next,
16071            window,
16072            cx,
16073        );
16074    }
16075
16076    pub fn go_to_hunk_before_or_after_position(
16077        &mut self,
16078        snapshot: &EditorSnapshot,
16079        position: Point,
16080        direction: Direction,
16081        window: &mut Window,
16082        cx: &mut Context<Editor>,
16083    ) {
16084        let row = if direction == Direction::Next {
16085            self.hunk_after_position(snapshot, position)
16086                .map(|hunk| hunk.row_range.start)
16087        } else {
16088            self.hunk_before_position(snapshot, position)
16089        };
16090
16091        if let Some(row) = row {
16092            let destination = Point::new(row.0, 0);
16093            let autoscroll = Autoscroll::center();
16094
16095            self.unfold_ranges(&[destination..destination], false, false, cx);
16096            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16097                s.select_ranges([destination..destination]);
16098            });
16099        }
16100    }
16101
16102    fn hunk_after_position(
16103        &mut self,
16104        snapshot: &EditorSnapshot,
16105        position: Point,
16106    ) -> Option<MultiBufferDiffHunk> {
16107        snapshot
16108            .buffer_snapshot()
16109            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16110            .find(|hunk| hunk.row_range.start.0 > position.row)
16111            .or_else(|| {
16112                snapshot
16113                    .buffer_snapshot()
16114                    .diff_hunks_in_range(Point::zero()..position)
16115                    .find(|hunk| hunk.row_range.end.0 < position.row)
16116            })
16117    }
16118
16119    fn go_to_prev_hunk(
16120        &mut self,
16121        _: &GoToPreviousHunk,
16122        window: &mut Window,
16123        cx: &mut Context<Self>,
16124    ) {
16125        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16126        let snapshot = self.snapshot(window, cx);
16127        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16128        self.go_to_hunk_before_or_after_position(
16129            &snapshot,
16130            selection.head(),
16131            Direction::Prev,
16132            window,
16133            cx,
16134        );
16135    }
16136
16137    fn hunk_before_position(
16138        &mut self,
16139        snapshot: &EditorSnapshot,
16140        position: Point,
16141    ) -> Option<MultiBufferRow> {
16142        snapshot
16143            .buffer_snapshot()
16144            .diff_hunk_before(position)
16145            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16146    }
16147
16148    fn go_to_next_change(
16149        &mut self,
16150        _: &GoToNextChange,
16151        window: &mut Window,
16152        cx: &mut Context<Self>,
16153    ) {
16154        if let Some(selections) = self
16155            .change_list
16156            .next_change(1, Direction::Next)
16157            .map(|s| s.to_vec())
16158        {
16159            self.change_selections(Default::default(), window, cx, |s| {
16160                let map = s.display_map();
16161                s.select_display_ranges(selections.iter().map(|a| {
16162                    let point = a.to_display_point(&map);
16163                    point..point
16164                }))
16165            })
16166        }
16167    }
16168
16169    fn go_to_previous_change(
16170        &mut self,
16171        _: &GoToPreviousChange,
16172        window: &mut Window,
16173        cx: &mut Context<Self>,
16174    ) {
16175        if let Some(selections) = self
16176            .change_list
16177            .next_change(1, Direction::Prev)
16178            .map(|s| s.to_vec())
16179        {
16180            self.change_selections(Default::default(), window, cx, |s| {
16181                let map = s.display_map();
16182                s.select_display_ranges(selections.iter().map(|a| {
16183                    let point = a.to_display_point(&map);
16184                    point..point
16185                }))
16186            })
16187        }
16188    }
16189
16190    pub fn go_to_next_document_highlight(
16191        &mut self,
16192        _: &GoToNextDocumentHighlight,
16193        window: &mut Window,
16194        cx: &mut Context<Self>,
16195    ) {
16196        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16197    }
16198
16199    pub fn go_to_prev_document_highlight(
16200        &mut self,
16201        _: &GoToPreviousDocumentHighlight,
16202        window: &mut Window,
16203        cx: &mut Context<Self>,
16204    ) {
16205        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16206    }
16207
16208    pub fn go_to_document_highlight_before_or_after_position(
16209        &mut self,
16210        direction: Direction,
16211        window: &mut Window,
16212        cx: &mut Context<Editor>,
16213    ) {
16214        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16215        let snapshot = self.snapshot(window, cx);
16216        let buffer = &snapshot.buffer_snapshot();
16217        let position = self
16218            .selections
16219            .newest::<Point>(&snapshot.display_snapshot)
16220            .head();
16221        let anchor_position = buffer.anchor_after(position);
16222
16223        // Get all document highlights (both read and write)
16224        let mut all_highlights = Vec::new();
16225
16226        if let Some((_, read_highlights)) = self
16227            .background_highlights
16228            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16229        {
16230            all_highlights.extend(read_highlights.iter());
16231        }
16232
16233        if let Some((_, write_highlights)) = self
16234            .background_highlights
16235            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16236        {
16237            all_highlights.extend(write_highlights.iter());
16238        }
16239
16240        if all_highlights.is_empty() {
16241            return;
16242        }
16243
16244        // Sort highlights by position
16245        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16246
16247        let target_highlight = match direction {
16248            Direction::Next => {
16249                // Find the first highlight after the current position
16250                all_highlights
16251                    .iter()
16252                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16253            }
16254            Direction::Prev => {
16255                // Find the last highlight before the current position
16256                all_highlights
16257                    .iter()
16258                    .rev()
16259                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16260            }
16261        };
16262
16263        if let Some(highlight) = target_highlight {
16264            let destination = highlight.start.to_point(buffer);
16265            let autoscroll = Autoscroll::center();
16266
16267            self.unfold_ranges(&[destination..destination], false, false, cx);
16268            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16269                s.select_ranges([destination..destination]);
16270            });
16271        }
16272    }
16273
16274    fn go_to_line<T: 'static>(
16275        &mut self,
16276        position: Anchor,
16277        highlight_color: Option<Hsla>,
16278        window: &mut Window,
16279        cx: &mut Context<Self>,
16280    ) {
16281        let snapshot = self.snapshot(window, cx).display_snapshot;
16282        let position = position.to_point(&snapshot.buffer_snapshot());
16283        let start = snapshot
16284            .buffer_snapshot()
16285            .clip_point(Point::new(position.row, 0), Bias::Left);
16286        let end = start + Point::new(1, 0);
16287        let start = snapshot.buffer_snapshot().anchor_before(start);
16288        let end = snapshot.buffer_snapshot().anchor_before(end);
16289
16290        self.highlight_rows::<T>(
16291            start..end,
16292            highlight_color
16293                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16294            Default::default(),
16295            cx,
16296        );
16297
16298        if self.buffer.read(cx).is_singleton() {
16299            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16300        }
16301    }
16302
16303    pub fn go_to_definition(
16304        &mut self,
16305        _: &GoToDefinition,
16306        window: &mut Window,
16307        cx: &mut Context<Self>,
16308    ) -> Task<Result<Navigated>> {
16309        let definition =
16310            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16311        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16312        cx.spawn_in(window, async move |editor, cx| {
16313            if definition.await? == Navigated::Yes {
16314                return Ok(Navigated::Yes);
16315            }
16316            match fallback_strategy {
16317                GoToDefinitionFallback::None => Ok(Navigated::No),
16318                GoToDefinitionFallback::FindAllReferences => {
16319                    match editor.update_in(cx, |editor, window, cx| {
16320                        editor.find_all_references(&FindAllReferences, window, cx)
16321                    })? {
16322                        Some(references) => references.await,
16323                        None => Ok(Navigated::No),
16324                    }
16325                }
16326            }
16327        })
16328    }
16329
16330    pub fn go_to_declaration(
16331        &mut self,
16332        _: &GoToDeclaration,
16333        window: &mut Window,
16334        cx: &mut Context<Self>,
16335    ) -> Task<Result<Navigated>> {
16336        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16337    }
16338
16339    pub fn go_to_declaration_split(
16340        &mut self,
16341        _: &GoToDeclaration,
16342        window: &mut Window,
16343        cx: &mut Context<Self>,
16344    ) -> Task<Result<Navigated>> {
16345        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16346    }
16347
16348    pub fn go_to_implementation(
16349        &mut self,
16350        _: &GoToImplementation,
16351        window: &mut Window,
16352        cx: &mut Context<Self>,
16353    ) -> Task<Result<Navigated>> {
16354        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16355    }
16356
16357    pub fn go_to_implementation_split(
16358        &mut self,
16359        _: &GoToImplementationSplit,
16360        window: &mut Window,
16361        cx: &mut Context<Self>,
16362    ) -> Task<Result<Navigated>> {
16363        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16364    }
16365
16366    pub fn go_to_type_definition(
16367        &mut self,
16368        _: &GoToTypeDefinition,
16369        window: &mut Window,
16370        cx: &mut Context<Self>,
16371    ) -> Task<Result<Navigated>> {
16372        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16373    }
16374
16375    pub fn go_to_definition_split(
16376        &mut self,
16377        _: &GoToDefinitionSplit,
16378        window: &mut Window,
16379        cx: &mut Context<Self>,
16380    ) -> Task<Result<Navigated>> {
16381        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16382    }
16383
16384    pub fn go_to_type_definition_split(
16385        &mut self,
16386        _: &GoToTypeDefinitionSplit,
16387        window: &mut Window,
16388        cx: &mut Context<Self>,
16389    ) -> Task<Result<Navigated>> {
16390        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16391    }
16392
16393    fn go_to_definition_of_kind(
16394        &mut self,
16395        kind: GotoDefinitionKind,
16396        split: bool,
16397        window: &mut Window,
16398        cx: &mut Context<Self>,
16399    ) -> Task<Result<Navigated>> {
16400        let Some(provider) = self.semantics_provider.clone() else {
16401            return Task::ready(Ok(Navigated::No));
16402        };
16403        let head = self
16404            .selections
16405            .newest::<usize>(&self.display_snapshot(cx))
16406            .head();
16407        let buffer = self.buffer.read(cx);
16408        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16409            return Task::ready(Ok(Navigated::No));
16410        };
16411        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16412            return Task::ready(Ok(Navigated::No));
16413        };
16414
16415        cx.spawn_in(window, async move |editor, cx| {
16416            let Some(definitions) = definitions.await? else {
16417                return Ok(Navigated::No);
16418            };
16419            let navigated = editor
16420                .update_in(cx, |editor, window, cx| {
16421                    editor.navigate_to_hover_links(
16422                        Some(kind),
16423                        definitions
16424                            .into_iter()
16425                            .filter(|location| {
16426                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16427                            })
16428                            .map(HoverLink::Text)
16429                            .collect::<Vec<_>>(),
16430                        split,
16431                        window,
16432                        cx,
16433                    )
16434                })?
16435                .await?;
16436            anyhow::Ok(navigated)
16437        })
16438    }
16439
16440    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16441        let selection = self.selections.newest_anchor();
16442        let head = selection.head();
16443        let tail = selection.tail();
16444
16445        let Some((buffer, start_position)) =
16446            self.buffer.read(cx).text_anchor_for_position(head, cx)
16447        else {
16448            return;
16449        };
16450
16451        let end_position = if head != tail {
16452            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16453                return;
16454            };
16455            Some(pos)
16456        } else {
16457            None
16458        };
16459
16460        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16461            let url = if let Some(end_pos) = end_position {
16462                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16463            } else {
16464                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16465            };
16466
16467            if let Some(url) = url {
16468                cx.update(|window, cx| {
16469                    if parse_zed_link(&url, cx).is_some() {
16470                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16471                    } else {
16472                        cx.open_url(&url);
16473                    }
16474                })?;
16475            }
16476
16477            anyhow::Ok(())
16478        });
16479
16480        url_finder.detach();
16481    }
16482
16483    pub fn open_selected_filename(
16484        &mut self,
16485        _: &OpenSelectedFilename,
16486        window: &mut Window,
16487        cx: &mut Context<Self>,
16488    ) {
16489        let Some(workspace) = self.workspace() else {
16490            return;
16491        };
16492
16493        let position = self.selections.newest_anchor().head();
16494
16495        let Some((buffer, buffer_position)) =
16496            self.buffer.read(cx).text_anchor_for_position(position, cx)
16497        else {
16498            return;
16499        };
16500
16501        let project = self.project.clone();
16502
16503        cx.spawn_in(window, async move |_, cx| {
16504            let result = find_file(&buffer, project, buffer_position, cx).await;
16505
16506            if let Some((_, path)) = result {
16507                workspace
16508                    .update_in(cx, |workspace, window, cx| {
16509                        workspace.open_resolved_path(path, window, cx)
16510                    })?
16511                    .await?;
16512            }
16513            anyhow::Ok(())
16514        })
16515        .detach();
16516    }
16517
16518    pub(crate) fn navigate_to_hover_links(
16519        &mut self,
16520        kind: Option<GotoDefinitionKind>,
16521        definitions: Vec<HoverLink>,
16522        split: bool,
16523        window: &mut Window,
16524        cx: &mut Context<Editor>,
16525    ) -> Task<Result<Navigated>> {
16526        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16527        let mut first_url_or_file = None;
16528        let definitions: Vec<_> = definitions
16529            .into_iter()
16530            .filter_map(|def| match def {
16531                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16532                HoverLink::InlayHint(lsp_location, server_id) => {
16533                    let computation =
16534                        self.compute_target_location(lsp_location, server_id, window, cx);
16535                    Some(cx.background_spawn(computation))
16536                }
16537                HoverLink::Url(url) => {
16538                    first_url_or_file = Some(Either::Left(url));
16539                    None
16540                }
16541                HoverLink::File(path) => {
16542                    first_url_or_file = Some(Either::Right(path));
16543                    None
16544                }
16545            })
16546            .collect();
16547
16548        let workspace = self.workspace();
16549
16550        cx.spawn_in(window, async move |editor, cx| {
16551            let locations: Vec<Location> = future::join_all(definitions)
16552                .await
16553                .into_iter()
16554                .filter_map(|location| location.transpose())
16555                .collect::<Result<_>>()
16556                .context("location tasks")?;
16557            let mut locations = cx.update(|_, cx| {
16558                locations
16559                    .into_iter()
16560                    .map(|location| {
16561                        let buffer = location.buffer.read(cx);
16562                        (location.buffer, location.range.to_point(buffer))
16563                    })
16564                    .into_group_map()
16565            })?;
16566            let mut num_locations = 0;
16567            for ranges in locations.values_mut() {
16568                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16569                ranges.dedup();
16570                num_locations += ranges.len();
16571            }
16572
16573            if num_locations > 1 {
16574                let Some(workspace) = workspace else {
16575                    return Ok(Navigated::No);
16576                };
16577
16578                let tab_kind = match kind {
16579                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16580                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16581                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16582                    Some(GotoDefinitionKind::Type) => "Types",
16583                };
16584                let title = editor
16585                    .update_in(cx, |_, _, cx| {
16586                        let target = locations
16587                            .iter()
16588                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16589                            .map(|(buffer, location)| {
16590                                buffer
16591                                    .read(cx)
16592                                    .text_for_range(location.clone())
16593                                    .collect::<String>()
16594                            })
16595                            .filter(|text| !text.contains('\n'))
16596                            .unique()
16597                            .take(3)
16598                            .join(", ");
16599                        if target.is_empty() {
16600                            tab_kind.to_owned()
16601                        } else {
16602                            format!("{tab_kind} for {target}")
16603                        }
16604                    })
16605                    .context("buffer title")?;
16606
16607                let opened = workspace
16608                    .update_in(cx, |workspace, window, cx| {
16609                        Self::open_locations_in_multibuffer(
16610                            workspace,
16611                            locations,
16612                            title,
16613                            split,
16614                            MultibufferSelectionMode::First,
16615                            window,
16616                            cx,
16617                        )
16618                    })
16619                    .is_ok();
16620
16621                anyhow::Ok(Navigated::from_bool(opened))
16622            } else if num_locations == 0 {
16623                // If there is one url or file, open it directly
16624                match first_url_or_file {
16625                    Some(Either::Left(url)) => {
16626                        cx.update(|_, cx| cx.open_url(&url))?;
16627                        Ok(Navigated::Yes)
16628                    }
16629                    Some(Either::Right(path)) => {
16630                        let Some(workspace) = workspace else {
16631                            return Ok(Navigated::No);
16632                        };
16633
16634                        workspace
16635                            .update_in(cx, |workspace, window, cx| {
16636                                workspace.open_resolved_path(path, window, cx)
16637                            })?
16638                            .await?;
16639                        Ok(Navigated::Yes)
16640                    }
16641                    None => Ok(Navigated::No),
16642                }
16643            } else {
16644                let Some(workspace) = workspace else {
16645                    return Ok(Navigated::No);
16646                };
16647
16648                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16649                let target_range = target_ranges.first().unwrap().clone();
16650
16651                editor.update_in(cx, |editor, window, cx| {
16652                    let range = target_range.to_point(target_buffer.read(cx));
16653                    let range = editor.range_for_match(&range, false);
16654                    let range = collapse_multiline_range(range);
16655
16656                    if !split
16657                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16658                    {
16659                        editor.go_to_singleton_buffer_range(range, window, cx);
16660                    } else {
16661                        let pane = workspace.read(cx).active_pane().clone();
16662                        window.defer(cx, move |window, cx| {
16663                            let target_editor: Entity<Self> =
16664                                workspace.update(cx, |workspace, cx| {
16665                                    let pane = if split {
16666                                        workspace.adjacent_pane(window, cx)
16667                                    } else {
16668                                        workspace.active_pane().clone()
16669                                    };
16670
16671                                    workspace.open_project_item(
16672                                        pane,
16673                                        target_buffer.clone(),
16674                                        true,
16675                                        true,
16676                                        window,
16677                                        cx,
16678                                    )
16679                                });
16680                            target_editor.update(cx, |target_editor, cx| {
16681                                // When selecting a definition in a different buffer, disable the nav history
16682                                // to avoid creating a history entry at the previous cursor location.
16683                                pane.update(cx, |pane, _| pane.disable_history());
16684                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16685                                pane.update(cx, |pane, _| pane.enable_history());
16686                            });
16687                        });
16688                    }
16689                    Navigated::Yes
16690                })
16691            }
16692        })
16693    }
16694
16695    fn compute_target_location(
16696        &self,
16697        lsp_location: lsp::Location,
16698        server_id: LanguageServerId,
16699        window: &mut Window,
16700        cx: &mut Context<Self>,
16701    ) -> Task<anyhow::Result<Option<Location>>> {
16702        let Some(project) = self.project.clone() else {
16703            return Task::ready(Ok(None));
16704        };
16705
16706        cx.spawn_in(window, async move |editor, cx| {
16707            let location_task = editor.update(cx, |_, cx| {
16708                project.update(cx, |project, cx| {
16709                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16710                })
16711            })?;
16712            let location = Some({
16713                let target_buffer_handle = location_task.await.context("open local buffer")?;
16714                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16715                    let target_start = target_buffer
16716                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16717                    let target_end = target_buffer
16718                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16719                    target_buffer.anchor_after(target_start)
16720                        ..target_buffer.anchor_before(target_end)
16721                })?;
16722                Location {
16723                    buffer: target_buffer_handle,
16724                    range,
16725                }
16726            });
16727            Ok(location)
16728        })
16729    }
16730
16731    fn go_to_next_reference(
16732        &mut self,
16733        _: &GoToNextReference,
16734        window: &mut Window,
16735        cx: &mut Context<Self>,
16736    ) {
16737        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16738        if let Some(task) = task {
16739            task.detach();
16740        };
16741    }
16742
16743    fn go_to_prev_reference(
16744        &mut self,
16745        _: &GoToPreviousReference,
16746        window: &mut Window,
16747        cx: &mut Context<Self>,
16748    ) {
16749        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16750        if let Some(task) = task {
16751            task.detach();
16752        };
16753    }
16754
16755    pub fn go_to_reference_before_or_after_position(
16756        &mut self,
16757        direction: Direction,
16758        count: usize,
16759        window: &mut Window,
16760        cx: &mut Context<Self>,
16761    ) -> Option<Task<Result<()>>> {
16762        let selection = self.selections.newest_anchor();
16763        let head = selection.head();
16764
16765        let multi_buffer = self.buffer.read(cx);
16766
16767        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16768        let workspace = self.workspace()?;
16769        let project = workspace.read(cx).project().clone();
16770        let references =
16771            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16772        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16773            let Some(locations) = references.await? else {
16774                return Ok(());
16775            };
16776
16777            if locations.is_empty() {
16778                // totally normal - the cursor may be on something which is not
16779                // a symbol (e.g. a keyword)
16780                log::info!("no references found under cursor");
16781                return Ok(());
16782            }
16783
16784            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16785
16786            let multi_buffer_snapshot =
16787                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16788
16789            let (locations, current_location_index) =
16790                multi_buffer.update(cx, |multi_buffer, cx| {
16791                    let mut locations = locations
16792                        .into_iter()
16793                        .filter_map(|loc| {
16794                            let start = multi_buffer.buffer_anchor_to_anchor(
16795                                &loc.buffer,
16796                                loc.range.start,
16797                                cx,
16798                            )?;
16799                            let end = multi_buffer.buffer_anchor_to_anchor(
16800                                &loc.buffer,
16801                                loc.range.end,
16802                                cx,
16803                            )?;
16804                            Some(start..end)
16805                        })
16806                        .collect::<Vec<_>>();
16807
16808                    // There is an O(n) implementation, but given this list will be
16809                    // small (usually <100 items), the extra O(log(n)) factor isn't
16810                    // worth the (surprisingly large amount of) extra complexity.
16811                    locations
16812                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16813
16814                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16815
16816                    let current_location_index = locations.iter().position(|loc| {
16817                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16818                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16819                    });
16820
16821                    (locations, current_location_index)
16822                })?;
16823
16824            let Some(current_location_index) = current_location_index else {
16825                // This indicates something has gone wrong, because we already
16826                // handle the "no references" case above
16827                log::error!(
16828                    "failed to find current reference under cursor. Total references: {}",
16829                    locations.len()
16830                );
16831                return Ok(());
16832            };
16833
16834            let destination_location_index = match direction {
16835                Direction::Next => (current_location_index + count) % locations.len(),
16836                Direction::Prev => {
16837                    (current_location_index + locations.len() - count % locations.len())
16838                        % locations.len()
16839                }
16840            };
16841
16842            // TODO(cameron): is this needed?
16843            // the thinking is to avoid "jumping to the current location" (avoid
16844            // polluting "jumplist" in vim terms)
16845            if current_location_index == destination_location_index {
16846                return Ok(());
16847            }
16848
16849            let Range { start, end } = locations[destination_location_index];
16850
16851            editor.update_in(cx, |editor, window, cx| {
16852                let effects = SelectionEffects::default();
16853
16854                editor.unfold_ranges(&[start..end], false, false, cx);
16855                editor.change_selections(effects, window, cx, |s| {
16856                    s.select_ranges([start..start]);
16857                });
16858            })?;
16859
16860            Ok(())
16861        }))
16862    }
16863
16864    pub fn find_all_references(
16865        &mut self,
16866        _: &FindAllReferences,
16867        window: &mut Window,
16868        cx: &mut Context<Self>,
16869    ) -> Option<Task<Result<Navigated>>> {
16870        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16871        let multi_buffer = self.buffer.read(cx);
16872        let head = selection.head();
16873
16874        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16875        let head_anchor = multi_buffer_snapshot.anchor_at(
16876            head,
16877            if head < selection.tail() {
16878                Bias::Right
16879            } else {
16880                Bias::Left
16881            },
16882        );
16883
16884        match self
16885            .find_all_references_task_sources
16886            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16887        {
16888            Ok(_) => {
16889                log::info!(
16890                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16891                );
16892                return None;
16893            }
16894            Err(i) => {
16895                self.find_all_references_task_sources.insert(i, head_anchor);
16896            }
16897        }
16898
16899        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16900        let workspace = self.workspace()?;
16901        let project = workspace.read(cx).project().clone();
16902        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16903        Some(cx.spawn_in(window, async move |editor, cx| {
16904            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16905                if let Ok(i) = editor
16906                    .find_all_references_task_sources
16907                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16908                {
16909                    editor.find_all_references_task_sources.remove(i);
16910                }
16911            });
16912
16913            let Some(locations) = references.await? else {
16914                return anyhow::Ok(Navigated::No);
16915            };
16916            let mut locations = cx.update(|_, cx| {
16917                locations
16918                    .into_iter()
16919                    .map(|location| {
16920                        let buffer = location.buffer.read(cx);
16921                        (location.buffer, location.range.to_point(buffer))
16922                    })
16923                    .into_group_map()
16924            })?;
16925            if locations.is_empty() {
16926                return anyhow::Ok(Navigated::No);
16927            }
16928            for ranges in locations.values_mut() {
16929                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16930                ranges.dedup();
16931            }
16932
16933            workspace.update_in(cx, |workspace, window, cx| {
16934                let target = locations
16935                    .iter()
16936                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16937                    .map(|(buffer, location)| {
16938                        buffer
16939                            .read(cx)
16940                            .text_for_range(location.clone())
16941                            .collect::<String>()
16942                    })
16943                    .filter(|text| !text.contains('\n'))
16944                    .unique()
16945                    .take(3)
16946                    .join(", ");
16947                let title = if target.is_empty() {
16948                    "References".to_owned()
16949                } else {
16950                    format!("References to {target}")
16951                };
16952                Self::open_locations_in_multibuffer(
16953                    workspace,
16954                    locations,
16955                    title,
16956                    false,
16957                    MultibufferSelectionMode::First,
16958                    window,
16959                    cx,
16960                );
16961                Navigated::Yes
16962            })
16963        }))
16964    }
16965
16966    /// Opens a multibuffer with the given project locations in it
16967    pub fn open_locations_in_multibuffer(
16968        workspace: &mut Workspace,
16969        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16970        title: String,
16971        split: bool,
16972        multibuffer_selection_mode: MultibufferSelectionMode,
16973        window: &mut Window,
16974        cx: &mut Context<Workspace>,
16975    ) {
16976        if locations.is_empty() {
16977            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16978            return;
16979        }
16980
16981        let capability = workspace.project().read(cx).capability();
16982        let mut ranges = <Vec<Range<Anchor>>>::new();
16983
16984        // a key to find existing multibuffer editors with the same set of locations
16985        // to prevent us from opening more and more multibuffer tabs for searches and the like
16986        let mut key = (title.clone(), vec![]);
16987        let excerpt_buffer = cx.new(|cx| {
16988            let key = &mut key.1;
16989            let mut multibuffer = MultiBuffer::new(capability);
16990            for (buffer, mut ranges_for_buffer) in locations {
16991                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16992                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16993                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16994                    PathKey::for_buffer(&buffer, cx),
16995                    buffer.clone(),
16996                    ranges_for_buffer,
16997                    multibuffer_context_lines(cx),
16998                    cx,
16999                );
17000                ranges.extend(new_ranges)
17001            }
17002
17003            multibuffer.with_title(title)
17004        });
17005        let existing = workspace.active_pane().update(cx, |pane, cx| {
17006            pane.items()
17007                .filter_map(|item| item.downcast::<Editor>())
17008                .find(|editor| {
17009                    editor
17010                        .read(cx)
17011                        .lookup_key
17012                        .as_ref()
17013                        .and_then(|it| {
17014                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17015                        })
17016                        .is_some_and(|it| *it == key)
17017                })
17018        });
17019        let editor = existing.unwrap_or_else(|| {
17020            cx.new(|cx| {
17021                let mut editor = Editor::for_multibuffer(
17022                    excerpt_buffer,
17023                    Some(workspace.project().clone()),
17024                    window,
17025                    cx,
17026                );
17027                editor.lookup_key = Some(Box::new(key));
17028                editor
17029            })
17030        });
17031        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17032            MultibufferSelectionMode::First => {
17033                if let Some(first_range) = ranges.first() {
17034                    editor.change_selections(
17035                        SelectionEffects::no_scroll(),
17036                        window,
17037                        cx,
17038                        |selections| {
17039                            selections.clear_disjoint();
17040                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17041                        },
17042                    );
17043                }
17044                editor.highlight_background::<Self>(
17045                    &ranges,
17046                    |theme| theme.colors().editor_highlighted_line_background,
17047                    cx,
17048                );
17049            }
17050            MultibufferSelectionMode::All => {
17051                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17052                    selections.clear_disjoint();
17053                    selections.select_anchor_ranges(ranges);
17054                });
17055            }
17056        });
17057
17058        let item = Box::new(editor);
17059        let item_id = item.item_id();
17060
17061        if split {
17062            let pane = workspace.adjacent_pane(window, cx);
17063            workspace.add_item(pane, item, None, true, true, window, cx);
17064        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17065            let (preview_item_id, preview_item_idx) =
17066                workspace.active_pane().read_with(cx, |pane, _| {
17067                    (pane.preview_item_id(), pane.preview_item_idx())
17068                });
17069
17070            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17071
17072            if let Some(preview_item_id) = preview_item_id {
17073                workspace.active_pane().update(cx, |pane, cx| {
17074                    pane.remove_item(preview_item_id, false, false, window, cx);
17075                });
17076            }
17077        } else {
17078            workspace.add_item_to_active_pane(item, None, true, window, cx);
17079        }
17080        workspace.active_pane().update(cx, |pane, cx| {
17081            pane.set_preview_item_id(Some(item_id), cx);
17082        });
17083    }
17084
17085    pub fn rename(
17086        &mut self,
17087        _: &Rename,
17088        window: &mut Window,
17089        cx: &mut Context<Self>,
17090    ) -> Option<Task<Result<()>>> {
17091        use language::ToOffset as _;
17092
17093        let provider = self.semantics_provider.clone()?;
17094        let selection = self.selections.newest_anchor().clone();
17095        let (cursor_buffer, cursor_buffer_position) = self
17096            .buffer
17097            .read(cx)
17098            .text_anchor_for_position(selection.head(), cx)?;
17099        let (tail_buffer, cursor_buffer_position_end) = self
17100            .buffer
17101            .read(cx)
17102            .text_anchor_for_position(selection.tail(), cx)?;
17103        if tail_buffer != cursor_buffer {
17104            return None;
17105        }
17106
17107        let snapshot = cursor_buffer.read(cx).snapshot();
17108        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17109        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17110        let prepare_rename = provider
17111            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17112            .unwrap_or_else(|| Task::ready(Ok(None)));
17113        drop(snapshot);
17114
17115        Some(cx.spawn_in(window, async move |this, cx| {
17116            let rename_range = if let Some(range) = prepare_rename.await? {
17117                Some(range)
17118            } else {
17119                this.update(cx, |this, cx| {
17120                    let buffer = this.buffer.read(cx).snapshot(cx);
17121                    let mut buffer_highlights = this
17122                        .document_highlights_for_position(selection.head(), &buffer)
17123                        .filter(|highlight| {
17124                            highlight.start.excerpt_id == selection.head().excerpt_id
17125                                && highlight.end.excerpt_id == selection.head().excerpt_id
17126                        });
17127                    buffer_highlights
17128                        .next()
17129                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17130                })?
17131            };
17132            if let Some(rename_range) = rename_range {
17133                this.update_in(cx, |this, window, cx| {
17134                    let snapshot = cursor_buffer.read(cx).snapshot();
17135                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17136                    let cursor_offset_in_rename_range =
17137                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17138                    let cursor_offset_in_rename_range_end =
17139                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17140
17141                    this.take_rename(false, window, cx);
17142                    let buffer = this.buffer.read(cx).read(cx);
17143                    let cursor_offset = selection.head().to_offset(&buffer);
17144                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17145                    let rename_end = rename_start + rename_buffer_range.len();
17146                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17147                    let mut old_highlight_id = None;
17148                    let old_name: Arc<str> = buffer
17149                        .chunks(rename_start..rename_end, true)
17150                        .map(|chunk| {
17151                            if old_highlight_id.is_none() {
17152                                old_highlight_id = chunk.syntax_highlight_id;
17153                            }
17154                            chunk.text
17155                        })
17156                        .collect::<String>()
17157                        .into();
17158
17159                    drop(buffer);
17160
17161                    // Position the selection in the rename editor so that it matches the current selection.
17162                    this.show_local_selections = false;
17163                    let rename_editor = cx.new(|cx| {
17164                        let mut editor = Editor::single_line(window, cx);
17165                        editor.buffer.update(cx, |buffer, cx| {
17166                            buffer.edit([(0..0, old_name.clone())], None, cx)
17167                        });
17168                        let rename_selection_range = match cursor_offset_in_rename_range
17169                            .cmp(&cursor_offset_in_rename_range_end)
17170                        {
17171                            Ordering::Equal => {
17172                                editor.select_all(&SelectAll, window, cx);
17173                                return editor;
17174                            }
17175                            Ordering::Less => {
17176                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17177                            }
17178                            Ordering::Greater => {
17179                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17180                            }
17181                        };
17182                        if rename_selection_range.end > old_name.len() {
17183                            editor.select_all(&SelectAll, window, cx);
17184                        } else {
17185                            editor.change_selections(Default::default(), window, cx, |s| {
17186                                s.select_ranges([rename_selection_range]);
17187                            });
17188                        }
17189                        editor
17190                    });
17191                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17192                        if e == &EditorEvent::Focused {
17193                            cx.emit(EditorEvent::FocusedIn)
17194                        }
17195                    })
17196                    .detach();
17197
17198                    let write_highlights =
17199                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17200                    let read_highlights =
17201                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17202                    let ranges = write_highlights
17203                        .iter()
17204                        .flat_map(|(_, ranges)| ranges.iter())
17205                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17206                        .cloned()
17207                        .collect();
17208
17209                    this.highlight_text::<Rename>(
17210                        ranges,
17211                        HighlightStyle {
17212                            fade_out: Some(0.6),
17213                            ..Default::default()
17214                        },
17215                        cx,
17216                    );
17217                    let rename_focus_handle = rename_editor.focus_handle(cx);
17218                    window.focus(&rename_focus_handle);
17219                    let block_id = this.insert_blocks(
17220                        [BlockProperties {
17221                            style: BlockStyle::Flex,
17222                            placement: BlockPlacement::Below(range.start),
17223                            height: Some(1),
17224                            render: Arc::new({
17225                                let rename_editor = rename_editor.clone();
17226                                move |cx: &mut BlockContext| {
17227                                    let mut text_style = cx.editor_style.text.clone();
17228                                    if let Some(highlight_style) = old_highlight_id
17229                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17230                                    {
17231                                        text_style = text_style.highlight(highlight_style);
17232                                    }
17233                                    div()
17234                                        .block_mouse_except_scroll()
17235                                        .pl(cx.anchor_x)
17236                                        .child(EditorElement::new(
17237                                            &rename_editor,
17238                                            EditorStyle {
17239                                                background: cx.theme().system().transparent,
17240                                                local_player: cx.editor_style.local_player,
17241                                                text: text_style,
17242                                                scrollbar_width: cx.editor_style.scrollbar_width,
17243                                                syntax: cx.editor_style.syntax.clone(),
17244                                                status: cx.editor_style.status.clone(),
17245                                                inlay_hints_style: HighlightStyle {
17246                                                    font_weight: Some(FontWeight::BOLD),
17247                                                    ..make_inlay_hints_style(cx.app)
17248                                                },
17249                                                edit_prediction_styles: make_suggestion_styles(
17250                                                    cx.app,
17251                                                ),
17252                                                ..EditorStyle::default()
17253                                            },
17254                                        ))
17255                                        .into_any_element()
17256                                }
17257                            }),
17258                            priority: 0,
17259                        }],
17260                        Some(Autoscroll::fit()),
17261                        cx,
17262                    )[0];
17263                    this.pending_rename = Some(RenameState {
17264                        range,
17265                        old_name,
17266                        editor: rename_editor,
17267                        block_id,
17268                    });
17269                })?;
17270            }
17271
17272            Ok(())
17273        }))
17274    }
17275
17276    pub fn confirm_rename(
17277        &mut self,
17278        _: &ConfirmRename,
17279        window: &mut Window,
17280        cx: &mut Context<Self>,
17281    ) -> Option<Task<Result<()>>> {
17282        let rename = self.take_rename(false, window, cx)?;
17283        let workspace = self.workspace()?.downgrade();
17284        let (buffer, start) = self
17285            .buffer
17286            .read(cx)
17287            .text_anchor_for_position(rename.range.start, cx)?;
17288        let (end_buffer, _) = self
17289            .buffer
17290            .read(cx)
17291            .text_anchor_for_position(rename.range.end, cx)?;
17292        if buffer != end_buffer {
17293            return None;
17294        }
17295
17296        let old_name = rename.old_name;
17297        let new_name = rename.editor.read(cx).text(cx);
17298
17299        let rename = self.semantics_provider.as_ref()?.perform_rename(
17300            &buffer,
17301            start,
17302            new_name.clone(),
17303            cx,
17304        )?;
17305
17306        Some(cx.spawn_in(window, async move |editor, cx| {
17307            let project_transaction = rename.await?;
17308            Self::open_project_transaction(
17309                &editor,
17310                workspace,
17311                project_transaction,
17312                format!("Rename: {}{}", old_name, new_name),
17313                cx,
17314            )
17315            .await?;
17316
17317            editor.update(cx, |editor, cx| {
17318                editor.refresh_document_highlights(cx);
17319            })?;
17320            Ok(())
17321        }))
17322    }
17323
17324    fn take_rename(
17325        &mut self,
17326        moving_cursor: bool,
17327        window: &mut Window,
17328        cx: &mut Context<Self>,
17329    ) -> Option<RenameState> {
17330        let rename = self.pending_rename.take()?;
17331        if rename.editor.focus_handle(cx).is_focused(window) {
17332            window.focus(&self.focus_handle);
17333        }
17334
17335        self.remove_blocks(
17336            [rename.block_id].into_iter().collect(),
17337            Some(Autoscroll::fit()),
17338            cx,
17339        );
17340        self.clear_highlights::<Rename>(cx);
17341        self.show_local_selections = true;
17342
17343        if moving_cursor {
17344            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17345                editor
17346                    .selections
17347                    .newest::<usize>(&editor.display_snapshot(cx))
17348                    .head()
17349            });
17350
17351            // Update the selection to match the position of the selection inside
17352            // the rename editor.
17353            let snapshot = self.buffer.read(cx).read(cx);
17354            let rename_range = rename.range.to_offset(&snapshot);
17355            let cursor_in_editor = snapshot
17356                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17357                .min(rename_range.end);
17358            drop(snapshot);
17359
17360            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17361                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17362            });
17363        } else {
17364            self.refresh_document_highlights(cx);
17365        }
17366
17367        Some(rename)
17368    }
17369
17370    pub fn pending_rename(&self) -> Option<&RenameState> {
17371        self.pending_rename.as_ref()
17372    }
17373
17374    fn format(
17375        &mut self,
17376        _: &Format,
17377        window: &mut Window,
17378        cx: &mut Context<Self>,
17379    ) -> Option<Task<Result<()>>> {
17380        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17381
17382        let project = match &self.project {
17383            Some(project) => project.clone(),
17384            None => return None,
17385        };
17386
17387        Some(self.perform_format(
17388            project,
17389            FormatTrigger::Manual,
17390            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17391            window,
17392            cx,
17393        ))
17394    }
17395
17396    fn format_selections(
17397        &mut self,
17398        _: &FormatSelections,
17399        window: &mut Window,
17400        cx: &mut Context<Self>,
17401    ) -> Option<Task<Result<()>>> {
17402        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17403
17404        let project = match &self.project {
17405            Some(project) => project.clone(),
17406            None => return None,
17407        };
17408
17409        let ranges = self
17410            .selections
17411            .all_adjusted(&self.display_snapshot(cx))
17412            .into_iter()
17413            .map(|selection| selection.range())
17414            .collect_vec();
17415
17416        Some(self.perform_format(
17417            project,
17418            FormatTrigger::Manual,
17419            FormatTarget::Ranges(ranges),
17420            window,
17421            cx,
17422        ))
17423    }
17424
17425    fn perform_format(
17426        &mut self,
17427        project: Entity<Project>,
17428        trigger: FormatTrigger,
17429        target: FormatTarget,
17430        window: &mut Window,
17431        cx: &mut Context<Self>,
17432    ) -> Task<Result<()>> {
17433        let buffer = self.buffer.clone();
17434        let (buffers, target) = match target {
17435            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17436            FormatTarget::Ranges(selection_ranges) => {
17437                let multi_buffer = buffer.read(cx);
17438                let snapshot = multi_buffer.read(cx);
17439                let mut buffers = HashSet::default();
17440                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17441                    BTreeMap::new();
17442                for selection_range in selection_ranges {
17443                    for (buffer, buffer_range, _) in
17444                        snapshot.range_to_buffer_ranges(selection_range)
17445                    {
17446                        let buffer_id = buffer.remote_id();
17447                        let start = buffer.anchor_before(buffer_range.start);
17448                        let end = buffer.anchor_after(buffer_range.end);
17449                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17450                        buffer_id_to_ranges
17451                            .entry(buffer_id)
17452                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17453                            .or_insert_with(|| vec![start..end]);
17454                    }
17455                }
17456                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17457            }
17458        };
17459
17460        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17461        let selections_prev = transaction_id_prev
17462            .and_then(|transaction_id_prev| {
17463                // default to selections as they were after the last edit, if we have them,
17464                // instead of how they are now.
17465                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17466                // will take you back to where you made the last edit, instead of staying where you scrolled
17467                self.selection_history
17468                    .transaction(transaction_id_prev)
17469                    .map(|t| t.0.clone())
17470            })
17471            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17472
17473        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17474        let format = project.update(cx, |project, cx| {
17475            project.format(buffers, target, true, trigger, cx)
17476        });
17477
17478        cx.spawn_in(window, async move |editor, cx| {
17479            let transaction = futures::select_biased! {
17480                transaction = format.log_err().fuse() => transaction,
17481                () = timeout => {
17482                    log::warn!("timed out waiting for formatting");
17483                    None
17484                }
17485            };
17486
17487            buffer
17488                .update(cx, |buffer, cx| {
17489                    if let Some(transaction) = transaction
17490                        && !buffer.is_singleton()
17491                    {
17492                        buffer.push_transaction(&transaction.0, cx);
17493                    }
17494                    cx.notify();
17495                })
17496                .ok();
17497
17498            if let Some(transaction_id_now) =
17499                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17500            {
17501                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17502                if has_new_transaction {
17503                    _ = editor.update(cx, |editor, _| {
17504                        editor
17505                            .selection_history
17506                            .insert_transaction(transaction_id_now, selections_prev);
17507                    });
17508                }
17509            }
17510
17511            Ok(())
17512        })
17513    }
17514
17515    fn organize_imports(
17516        &mut self,
17517        _: &OrganizeImports,
17518        window: &mut Window,
17519        cx: &mut Context<Self>,
17520    ) -> Option<Task<Result<()>>> {
17521        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17522        let project = match &self.project {
17523            Some(project) => project.clone(),
17524            None => return None,
17525        };
17526        Some(self.perform_code_action_kind(
17527            project,
17528            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17529            window,
17530            cx,
17531        ))
17532    }
17533
17534    fn perform_code_action_kind(
17535        &mut self,
17536        project: Entity<Project>,
17537        kind: CodeActionKind,
17538        window: &mut Window,
17539        cx: &mut Context<Self>,
17540    ) -> Task<Result<()>> {
17541        let buffer = self.buffer.clone();
17542        let buffers = buffer.read(cx).all_buffers();
17543        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17544        let apply_action = project.update(cx, |project, cx| {
17545            project.apply_code_action_kind(buffers, kind, true, cx)
17546        });
17547        cx.spawn_in(window, async move |_, cx| {
17548            let transaction = futures::select_biased! {
17549                () = timeout => {
17550                    log::warn!("timed out waiting for executing code action");
17551                    None
17552                }
17553                transaction = apply_action.log_err().fuse() => transaction,
17554            };
17555            buffer
17556                .update(cx, |buffer, cx| {
17557                    // check if we need this
17558                    if let Some(transaction) = transaction
17559                        && !buffer.is_singleton()
17560                    {
17561                        buffer.push_transaction(&transaction.0, cx);
17562                    }
17563                    cx.notify();
17564                })
17565                .ok();
17566            Ok(())
17567        })
17568    }
17569
17570    pub fn restart_language_server(
17571        &mut self,
17572        _: &RestartLanguageServer,
17573        _: &mut Window,
17574        cx: &mut Context<Self>,
17575    ) {
17576        if let Some(project) = self.project.clone() {
17577            self.buffer.update(cx, |multi_buffer, cx| {
17578                project.update(cx, |project, cx| {
17579                    project.restart_language_servers_for_buffers(
17580                        multi_buffer.all_buffers().into_iter().collect(),
17581                        HashSet::default(),
17582                        cx,
17583                    );
17584                });
17585            })
17586        }
17587    }
17588
17589    pub fn stop_language_server(
17590        &mut self,
17591        _: &StopLanguageServer,
17592        _: &mut Window,
17593        cx: &mut Context<Self>,
17594    ) {
17595        if let Some(project) = self.project.clone() {
17596            self.buffer.update(cx, |multi_buffer, cx| {
17597                project.update(cx, |project, cx| {
17598                    project.stop_language_servers_for_buffers(
17599                        multi_buffer.all_buffers().into_iter().collect(),
17600                        HashSet::default(),
17601                        cx,
17602                    );
17603                });
17604            });
17605            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17606        }
17607    }
17608
17609    fn cancel_language_server_work(
17610        workspace: &mut Workspace,
17611        _: &actions::CancelLanguageServerWork,
17612        _: &mut Window,
17613        cx: &mut Context<Workspace>,
17614    ) {
17615        let project = workspace.project();
17616        let buffers = workspace
17617            .active_item(cx)
17618            .and_then(|item| item.act_as::<Editor>(cx))
17619            .map_or(HashSet::default(), |editor| {
17620                editor.read(cx).buffer.read(cx).all_buffers()
17621            });
17622        project.update(cx, |project, cx| {
17623            project.cancel_language_server_work_for_buffers(buffers, cx);
17624        });
17625    }
17626
17627    fn show_character_palette(
17628        &mut self,
17629        _: &ShowCharacterPalette,
17630        window: &mut Window,
17631        _: &mut Context<Self>,
17632    ) {
17633        window.show_character_palette();
17634    }
17635
17636    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17637        if !self.diagnostics_enabled() {
17638            return;
17639        }
17640
17641        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17642            let buffer = self.buffer.read(cx).snapshot(cx);
17643            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17644            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17645            let is_valid = buffer
17646                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17647                .any(|entry| {
17648                    entry.diagnostic.is_primary
17649                        && !entry.range.is_empty()
17650                        && entry.range.start == primary_range_start
17651                        && entry.diagnostic.message == active_diagnostics.active_message
17652                });
17653
17654            if !is_valid {
17655                self.dismiss_diagnostics(cx);
17656            }
17657        }
17658    }
17659
17660    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17661        match &self.active_diagnostics {
17662            ActiveDiagnostic::Group(group) => Some(group),
17663            _ => None,
17664        }
17665    }
17666
17667    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17668        if !self.diagnostics_enabled() {
17669            return;
17670        }
17671        self.dismiss_diagnostics(cx);
17672        self.active_diagnostics = ActiveDiagnostic::All;
17673    }
17674
17675    fn activate_diagnostics(
17676        &mut self,
17677        buffer_id: BufferId,
17678        diagnostic: DiagnosticEntryRef<'_, usize>,
17679        window: &mut Window,
17680        cx: &mut Context<Self>,
17681    ) {
17682        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17683            return;
17684        }
17685        self.dismiss_diagnostics(cx);
17686        let snapshot = self.snapshot(window, cx);
17687        let buffer = self.buffer.read(cx).snapshot(cx);
17688        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17689            return;
17690        };
17691
17692        let diagnostic_group = buffer
17693            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17694            .collect::<Vec<_>>();
17695
17696        let blocks =
17697            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17698
17699        let blocks = self.display_map.update(cx, |display_map, cx| {
17700            display_map.insert_blocks(blocks, cx).into_iter().collect()
17701        });
17702        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17703            active_range: buffer.anchor_before(diagnostic.range.start)
17704                ..buffer.anchor_after(diagnostic.range.end),
17705            active_message: diagnostic.diagnostic.message.clone(),
17706            group_id: diagnostic.diagnostic.group_id,
17707            blocks,
17708        });
17709        cx.notify();
17710    }
17711
17712    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17713        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17714            return;
17715        };
17716
17717        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17718        if let ActiveDiagnostic::Group(group) = prev {
17719            self.display_map.update(cx, |display_map, cx| {
17720                display_map.remove_blocks(group.blocks, cx);
17721            });
17722            cx.notify();
17723        }
17724    }
17725
17726    /// Disable inline diagnostics rendering for this editor.
17727    pub fn disable_inline_diagnostics(&mut self) {
17728        self.inline_diagnostics_enabled = false;
17729        self.inline_diagnostics_update = Task::ready(());
17730        self.inline_diagnostics.clear();
17731    }
17732
17733    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17734        self.diagnostics_enabled = false;
17735        self.dismiss_diagnostics(cx);
17736        self.inline_diagnostics_update = Task::ready(());
17737        self.inline_diagnostics.clear();
17738    }
17739
17740    pub fn disable_word_completions(&mut self) {
17741        self.word_completions_enabled = false;
17742    }
17743
17744    pub fn diagnostics_enabled(&self) -> bool {
17745        self.diagnostics_enabled && self.mode.is_full()
17746    }
17747
17748    pub fn inline_diagnostics_enabled(&self) -> bool {
17749        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17750    }
17751
17752    pub fn show_inline_diagnostics(&self) -> bool {
17753        self.show_inline_diagnostics
17754    }
17755
17756    pub fn toggle_inline_diagnostics(
17757        &mut self,
17758        _: &ToggleInlineDiagnostics,
17759        window: &mut Window,
17760        cx: &mut Context<Editor>,
17761    ) {
17762        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17763        self.refresh_inline_diagnostics(false, window, cx);
17764    }
17765
17766    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17767        self.diagnostics_max_severity = severity;
17768        self.display_map.update(cx, |display_map, _| {
17769            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17770        });
17771    }
17772
17773    pub fn toggle_diagnostics(
17774        &mut self,
17775        _: &ToggleDiagnostics,
17776        window: &mut Window,
17777        cx: &mut Context<Editor>,
17778    ) {
17779        if !self.diagnostics_enabled() {
17780            return;
17781        }
17782
17783        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17784            EditorSettings::get_global(cx)
17785                .diagnostics_max_severity
17786                .filter(|severity| severity != &DiagnosticSeverity::Off)
17787                .unwrap_or(DiagnosticSeverity::Hint)
17788        } else {
17789            DiagnosticSeverity::Off
17790        };
17791        self.set_max_diagnostics_severity(new_severity, cx);
17792        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17793            self.active_diagnostics = ActiveDiagnostic::None;
17794            self.inline_diagnostics_update = Task::ready(());
17795            self.inline_diagnostics.clear();
17796        } else {
17797            self.refresh_inline_diagnostics(false, window, cx);
17798        }
17799
17800        cx.notify();
17801    }
17802
17803    pub fn toggle_minimap(
17804        &mut self,
17805        _: &ToggleMinimap,
17806        window: &mut Window,
17807        cx: &mut Context<Editor>,
17808    ) {
17809        if self.supports_minimap(cx) {
17810            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17811        }
17812    }
17813
17814    fn refresh_inline_diagnostics(
17815        &mut self,
17816        debounce: bool,
17817        window: &mut Window,
17818        cx: &mut Context<Self>,
17819    ) {
17820        let max_severity = ProjectSettings::get_global(cx)
17821            .diagnostics
17822            .inline
17823            .max_severity
17824            .unwrap_or(self.diagnostics_max_severity);
17825
17826        if !self.inline_diagnostics_enabled()
17827            || !self.diagnostics_enabled()
17828            || !self.show_inline_diagnostics
17829            || max_severity == DiagnosticSeverity::Off
17830        {
17831            self.inline_diagnostics_update = Task::ready(());
17832            self.inline_diagnostics.clear();
17833            return;
17834        }
17835
17836        let debounce_ms = ProjectSettings::get_global(cx)
17837            .diagnostics
17838            .inline
17839            .update_debounce_ms;
17840        let debounce = if debounce && debounce_ms > 0 {
17841            Some(Duration::from_millis(debounce_ms))
17842        } else {
17843            None
17844        };
17845        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17846            if let Some(debounce) = debounce {
17847                cx.background_executor().timer(debounce).await;
17848            }
17849            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17850                editor
17851                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17852                    .ok()
17853            }) else {
17854                return;
17855            };
17856
17857            let new_inline_diagnostics = cx
17858                .background_spawn(async move {
17859                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17860                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17861                        let message = diagnostic_entry
17862                            .diagnostic
17863                            .message
17864                            .split_once('\n')
17865                            .map(|(line, _)| line)
17866                            .map(SharedString::new)
17867                            .unwrap_or_else(|| {
17868                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17869                            });
17870                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17871                        let (Ok(i) | Err(i)) = inline_diagnostics
17872                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17873                        inline_diagnostics.insert(
17874                            i,
17875                            (
17876                                start_anchor,
17877                                InlineDiagnostic {
17878                                    message,
17879                                    group_id: diagnostic_entry.diagnostic.group_id,
17880                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17881                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17882                                    severity: diagnostic_entry.diagnostic.severity,
17883                                },
17884                            ),
17885                        );
17886                    }
17887                    inline_diagnostics
17888                })
17889                .await;
17890
17891            editor
17892                .update(cx, |editor, cx| {
17893                    editor.inline_diagnostics = new_inline_diagnostics;
17894                    cx.notify();
17895                })
17896                .ok();
17897        });
17898    }
17899
17900    fn pull_diagnostics(
17901        &mut self,
17902        buffer_id: Option<BufferId>,
17903        window: &Window,
17904        cx: &mut Context<Self>,
17905    ) -> Option<()> {
17906        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
17907            return None;
17908        }
17909        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17910            .diagnostics
17911            .lsp_pull_diagnostics;
17912        if !pull_diagnostics_settings.enabled {
17913            return None;
17914        }
17915        let project = self.project()?.downgrade();
17916        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17917        let mut buffers = self.buffer.read(cx).all_buffers();
17918        buffers.retain(|buffer| {
17919            let buffer_id_to_retain = buffer.read(cx).remote_id();
17920            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17921                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17922        });
17923        if buffers.is_empty() {
17924            self.pull_diagnostics_task = Task::ready(());
17925            return None;
17926        }
17927
17928        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17929            cx.background_executor().timer(debounce).await;
17930
17931            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17932                buffers
17933                    .into_iter()
17934                    .filter_map(|buffer| {
17935                        project
17936                            .update(cx, |project, cx| {
17937                                project.lsp_store().update(cx, |lsp_store, cx| {
17938                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17939                                })
17940                            })
17941                            .ok()
17942                    })
17943                    .collect::<FuturesUnordered<_>>()
17944            }) else {
17945                return;
17946            };
17947
17948            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17949                match pull_task {
17950                    Ok(()) => {
17951                        if editor
17952                            .update_in(cx, |editor, window, cx| {
17953                                editor.update_diagnostics_state(window, cx);
17954                            })
17955                            .is_err()
17956                        {
17957                            return;
17958                        }
17959                    }
17960                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17961                }
17962            }
17963        });
17964
17965        Some(())
17966    }
17967
17968    pub fn set_selections_from_remote(
17969        &mut self,
17970        selections: Vec<Selection<Anchor>>,
17971        pending_selection: Option<Selection<Anchor>>,
17972        window: &mut Window,
17973        cx: &mut Context<Self>,
17974    ) {
17975        let old_cursor_position = self.selections.newest_anchor().head();
17976        self.selections.change_with(cx, |s| {
17977            s.select_anchors(selections);
17978            if let Some(pending_selection) = pending_selection {
17979                s.set_pending(pending_selection, SelectMode::Character);
17980            } else {
17981                s.clear_pending();
17982            }
17983        });
17984        self.selections_did_change(
17985            false,
17986            &old_cursor_position,
17987            SelectionEffects::default(),
17988            window,
17989            cx,
17990        );
17991    }
17992
17993    pub fn transact(
17994        &mut self,
17995        window: &mut Window,
17996        cx: &mut Context<Self>,
17997        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17998    ) -> Option<TransactionId> {
17999        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18000            this.start_transaction_at(Instant::now(), window, cx);
18001            update(this, window, cx);
18002            this.end_transaction_at(Instant::now(), cx)
18003        })
18004    }
18005
18006    pub fn start_transaction_at(
18007        &mut self,
18008        now: Instant,
18009        window: &mut Window,
18010        cx: &mut Context<Self>,
18011    ) -> Option<TransactionId> {
18012        self.end_selection(window, cx);
18013        if let Some(tx_id) = self
18014            .buffer
18015            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18016        {
18017            self.selection_history
18018                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18019            cx.emit(EditorEvent::TransactionBegun {
18020                transaction_id: tx_id,
18021            });
18022            Some(tx_id)
18023        } else {
18024            None
18025        }
18026    }
18027
18028    pub fn end_transaction_at(
18029        &mut self,
18030        now: Instant,
18031        cx: &mut Context<Self>,
18032    ) -> Option<TransactionId> {
18033        if let Some(transaction_id) = self
18034            .buffer
18035            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18036        {
18037            if let Some((_, end_selections)) =
18038                self.selection_history.transaction_mut(transaction_id)
18039            {
18040                *end_selections = Some(self.selections.disjoint_anchors_arc());
18041            } else {
18042                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18043            }
18044
18045            cx.emit(EditorEvent::Edited { transaction_id });
18046            Some(transaction_id)
18047        } else {
18048            None
18049        }
18050    }
18051
18052    pub fn modify_transaction_selection_history(
18053        &mut self,
18054        transaction_id: TransactionId,
18055        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18056    ) -> bool {
18057        self.selection_history
18058            .transaction_mut(transaction_id)
18059            .map(modify)
18060            .is_some()
18061    }
18062
18063    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18064        if self.selection_mark_mode {
18065            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18066                s.move_with(|_, sel| {
18067                    sel.collapse_to(sel.head(), SelectionGoal::None);
18068                });
18069            })
18070        }
18071        self.selection_mark_mode = true;
18072        cx.notify();
18073    }
18074
18075    pub fn swap_selection_ends(
18076        &mut self,
18077        _: &actions::SwapSelectionEnds,
18078        window: &mut Window,
18079        cx: &mut Context<Self>,
18080    ) {
18081        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18082            s.move_with(|_, sel| {
18083                if sel.start != sel.end {
18084                    sel.reversed = !sel.reversed
18085                }
18086            });
18087        });
18088        self.request_autoscroll(Autoscroll::newest(), cx);
18089        cx.notify();
18090    }
18091
18092    pub fn toggle_focus(
18093        workspace: &mut Workspace,
18094        _: &actions::ToggleFocus,
18095        window: &mut Window,
18096        cx: &mut Context<Workspace>,
18097    ) {
18098        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18099            return;
18100        };
18101        workspace.activate_item(&item, true, true, window, cx);
18102    }
18103
18104    pub fn toggle_fold(
18105        &mut self,
18106        _: &actions::ToggleFold,
18107        window: &mut Window,
18108        cx: &mut Context<Self>,
18109    ) {
18110        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18111            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18112            let selection = self.selections.newest::<Point>(&display_map);
18113
18114            let range = if selection.is_empty() {
18115                let point = selection.head().to_display_point(&display_map);
18116                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18117                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18118                    .to_point(&display_map);
18119                start..end
18120            } else {
18121                selection.range()
18122            };
18123            if display_map.folds_in_range(range).next().is_some() {
18124                self.unfold_lines(&Default::default(), window, cx)
18125            } else {
18126                self.fold(&Default::default(), window, cx)
18127            }
18128        } else {
18129            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18130            let buffer_ids: HashSet<_> = self
18131                .selections
18132                .disjoint_anchor_ranges()
18133                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18134                .collect();
18135
18136            let should_unfold = buffer_ids
18137                .iter()
18138                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18139
18140            for buffer_id in buffer_ids {
18141                if should_unfold {
18142                    self.unfold_buffer(buffer_id, cx);
18143                } else {
18144                    self.fold_buffer(buffer_id, cx);
18145                }
18146            }
18147        }
18148    }
18149
18150    pub fn toggle_fold_recursive(
18151        &mut self,
18152        _: &actions::ToggleFoldRecursive,
18153        window: &mut Window,
18154        cx: &mut Context<Self>,
18155    ) {
18156        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18157
18158        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18159        let range = if selection.is_empty() {
18160            let point = selection.head().to_display_point(&display_map);
18161            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18162            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18163                .to_point(&display_map);
18164            start..end
18165        } else {
18166            selection.range()
18167        };
18168        if display_map.folds_in_range(range).next().is_some() {
18169            self.unfold_recursive(&Default::default(), window, cx)
18170        } else {
18171            self.fold_recursive(&Default::default(), window, cx)
18172        }
18173    }
18174
18175    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18176        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18177            let mut to_fold = Vec::new();
18178            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18179            let selections = self.selections.all_adjusted(&display_map);
18180
18181            for selection in selections {
18182                let range = selection.range().sorted();
18183                let buffer_start_row = range.start.row;
18184
18185                if range.start.row != range.end.row {
18186                    let mut found = false;
18187                    let mut row = range.start.row;
18188                    while row <= range.end.row {
18189                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18190                        {
18191                            found = true;
18192                            row = crease.range().end.row + 1;
18193                            to_fold.push(crease);
18194                        } else {
18195                            row += 1
18196                        }
18197                    }
18198                    if found {
18199                        continue;
18200                    }
18201                }
18202
18203                for row in (0..=range.start.row).rev() {
18204                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18205                        && crease.range().end.row >= buffer_start_row
18206                    {
18207                        to_fold.push(crease);
18208                        if row <= range.start.row {
18209                            break;
18210                        }
18211                    }
18212                }
18213            }
18214
18215            self.fold_creases(to_fold, true, window, cx);
18216        } else {
18217            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18218            let buffer_ids = self
18219                .selections
18220                .disjoint_anchor_ranges()
18221                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18222                .collect::<HashSet<_>>();
18223            for buffer_id in buffer_ids {
18224                self.fold_buffer(buffer_id, cx);
18225            }
18226        }
18227    }
18228
18229    pub fn toggle_fold_all(
18230        &mut self,
18231        _: &actions::ToggleFoldAll,
18232        window: &mut Window,
18233        cx: &mut Context<Self>,
18234    ) {
18235        if self.buffer.read(cx).is_singleton() {
18236            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18237            let has_folds = display_map
18238                .folds_in_range(0..display_map.buffer_snapshot().len())
18239                .next()
18240                .is_some();
18241
18242            if has_folds {
18243                self.unfold_all(&actions::UnfoldAll, window, cx);
18244            } else {
18245                self.fold_all(&actions::FoldAll, window, cx);
18246            }
18247        } else {
18248            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18249            let should_unfold = buffer_ids
18250                .iter()
18251                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18252
18253            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18254                editor
18255                    .update_in(cx, |editor, _, cx| {
18256                        for buffer_id in buffer_ids {
18257                            if should_unfold {
18258                                editor.unfold_buffer(buffer_id, cx);
18259                            } else {
18260                                editor.fold_buffer(buffer_id, cx);
18261                            }
18262                        }
18263                    })
18264                    .ok();
18265            });
18266        }
18267    }
18268
18269    fn fold_at_level(
18270        &mut self,
18271        fold_at: &FoldAtLevel,
18272        window: &mut Window,
18273        cx: &mut Context<Self>,
18274    ) {
18275        if !self.buffer.read(cx).is_singleton() {
18276            return;
18277        }
18278
18279        let fold_at_level = fold_at.0;
18280        let snapshot = self.buffer.read(cx).snapshot(cx);
18281        let mut to_fold = Vec::new();
18282        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18283
18284        let row_ranges_to_keep: Vec<Range<u32>> = self
18285            .selections
18286            .all::<Point>(&self.display_snapshot(cx))
18287            .into_iter()
18288            .map(|sel| sel.start.row..sel.end.row)
18289            .collect();
18290
18291        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18292            while start_row < end_row {
18293                match self
18294                    .snapshot(window, cx)
18295                    .crease_for_buffer_row(MultiBufferRow(start_row))
18296                {
18297                    Some(crease) => {
18298                        let nested_start_row = crease.range().start.row + 1;
18299                        let nested_end_row = crease.range().end.row;
18300
18301                        if current_level < fold_at_level {
18302                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18303                        } else if current_level == fold_at_level {
18304                            // Fold iff there is no selection completely contained within the fold region
18305                            if !row_ranges_to_keep.iter().any(|selection| {
18306                                selection.end >= nested_start_row
18307                                    && selection.start <= nested_end_row
18308                            }) {
18309                                to_fold.push(crease);
18310                            }
18311                        }
18312
18313                        start_row = nested_end_row + 1;
18314                    }
18315                    None => start_row += 1,
18316                }
18317            }
18318        }
18319
18320        self.fold_creases(to_fold, true, window, cx);
18321    }
18322
18323    pub fn fold_at_level_1(
18324        &mut self,
18325        _: &actions::FoldAtLevel1,
18326        window: &mut Window,
18327        cx: &mut Context<Self>,
18328    ) {
18329        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18330    }
18331
18332    pub fn fold_at_level_2(
18333        &mut self,
18334        _: &actions::FoldAtLevel2,
18335        window: &mut Window,
18336        cx: &mut Context<Self>,
18337    ) {
18338        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18339    }
18340
18341    pub fn fold_at_level_3(
18342        &mut self,
18343        _: &actions::FoldAtLevel3,
18344        window: &mut Window,
18345        cx: &mut Context<Self>,
18346    ) {
18347        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18348    }
18349
18350    pub fn fold_at_level_4(
18351        &mut self,
18352        _: &actions::FoldAtLevel4,
18353        window: &mut Window,
18354        cx: &mut Context<Self>,
18355    ) {
18356        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18357    }
18358
18359    pub fn fold_at_level_5(
18360        &mut self,
18361        _: &actions::FoldAtLevel5,
18362        window: &mut Window,
18363        cx: &mut Context<Self>,
18364    ) {
18365        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18366    }
18367
18368    pub fn fold_at_level_6(
18369        &mut self,
18370        _: &actions::FoldAtLevel6,
18371        window: &mut Window,
18372        cx: &mut Context<Self>,
18373    ) {
18374        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18375    }
18376
18377    pub fn fold_at_level_7(
18378        &mut self,
18379        _: &actions::FoldAtLevel7,
18380        window: &mut Window,
18381        cx: &mut Context<Self>,
18382    ) {
18383        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18384    }
18385
18386    pub fn fold_at_level_8(
18387        &mut self,
18388        _: &actions::FoldAtLevel8,
18389        window: &mut Window,
18390        cx: &mut Context<Self>,
18391    ) {
18392        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18393    }
18394
18395    pub fn fold_at_level_9(
18396        &mut self,
18397        _: &actions::FoldAtLevel9,
18398        window: &mut Window,
18399        cx: &mut Context<Self>,
18400    ) {
18401        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18402    }
18403
18404    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18405        if self.buffer.read(cx).is_singleton() {
18406            let mut fold_ranges = Vec::new();
18407            let snapshot = self.buffer.read(cx).snapshot(cx);
18408
18409            for row in 0..snapshot.max_row().0 {
18410                if let Some(foldable_range) = self
18411                    .snapshot(window, cx)
18412                    .crease_for_buffer_row(MultiBufferRow(row))
18413                {
18414                    fold_ranges.push(foldable_range);
18415                }
18416            }
18417
18418            self.fold_creases(fold_ranges, true, window, cx);
18419        } else {
18420            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18421                editor
18422                    .update_in(cx, |editor, _, cx| {
18423                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18424                            editor.fold_buffer(buffer_id, cx);
18425                        }
18426                    })
18427                    .ok();
18428            });
18429        }
18430    }
18431
18432    pub fn fold_function_bodies(
18433        &mut self,
18434        _: &actions::FoldFunctionBodies,
18435        window: &mut Window,
18436        cx: &mut Context<Self>,
18437    ) {
18438        let snapshot = self.buffer.read(cx).snapshot(cx);
18439
18440        let ranges = snapshot
18441            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18442            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18443            .collect::<Vec<_>>();
18444
18445        let creases = ranges
18446            .into_iter()
18447            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18448            .collect();
18449
18450        self.fold_creases(creases, true, window, cx);
18451    }
18452
18453    pub fn fold_recursive(
18454        &mut self,
18455        _: &actions::FoldRecursive,
18456        window: &mut Window,
18457        cx: &mut Context<Self>,
18458    ) {
18459        let mut to_fold = Vec::new();
18460        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18461        let selections = self.selections.all_adjusted(&display_map);
18462
18463        for selection in selections {
18464            let range = selection.range().sorted();
18465            let buffer_start_row = range.start.row;
18466
18467            if range.start.row != range.end.row {
18468                let mut found = false;
18469                for row in range.start.row..=range.end.row {
18470                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18471                        found = true;
18472                        to_fold.push(crease);
18473                    }
18474                }
18475                if found {
18476                    continue;
18477                }
18478            }
18479
18480            for row in (0..=range.start.row).rev() {
18481                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18482                    if crease.range().end.row >= buffer_start_row {
18483                        to_fold.push(crease);
18484                    } else {
18485                        break;
18486                    }
18487                }
18488            }
18489        }
18490
18491        self.fold_creases(to_fold, true, window, cx);
18492    }
18493
18494    pub fn fold_at(
18495        &mut self,
18496        buffer_row: MultiBufferRow,
18497        window: &mut Window,
18498        cx: &mut Context<Self>,
18499    ) {
18500        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18501
18502        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18503            let autoscroll = self
18504                .selections
18505                .all::<Point>(&display_map)
18506                .iter()
18507                .any(|selection| crease.range().overlaps(&selection.range()));
18508
18509            self.fold_creases(vec![crease], autoscroll, window, cx);
18510        }
18511    }
18512
18513    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18514        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18515            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18516            let buffer = display_map.buffer_snapshot();
18517            let selections = self.selections.all::<Point>(&display_map);
18518            let ranges = selections
18519                .iter()
18520                .map(|s| {
18521                    let range = s.display_range(&display_map).sorted();
18522                    let mut start = range.start.to_point(&display_map);
18523                    let mut end = range.end.to_point(&display_map);
18524                    start.column = 0;
18525                    end.column = buffer.line_len(MultiBufferRow(end.row));
18526                    start..end
18527                })
18528                .collect::<Vec<_>>();
18529
18530            self.unfold_ranges(&ranges, true, true, cx);
18531        } else {
18532            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18533            let buffer_ids = self
18534                .selections
18535                .disjoint_anchor_ranges()
18536                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18537                .collect::<HashSet<_>>();
18538            for buffer_id in buffer_ids {
18539                self.unfold_buffer(buffer_id, cx);
18540            }
18541        }
18542    }
18543
18544    pub fn unfold_recursive(
18545        &mut self,
18546        _: &UnfoldRecursive,
18547        _window: &mut Window,
18548        cx: &mut Context<Self>,
18549    ) {
18550        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18551        let selections = self.selections.all::<Point>(&display_map);
18552        let ranges = selections
18553            .iter()
18554            .map(|s| {
18555                let mut range = s.display_range(&display_map).sorted();
18556                *range.start.column_mut() = 0;
18557                *range.end.column_mut() = display_map.line_len(range.end.row());
18558                let start = range.start.to_point(&display_map);
18559                let end = range.end.to_point(&display_map);
18560                start..end
18561            })
18562            .collect::<Vec<_>>();
18563
18564        self.unfold_ranges(&ranges, true, true, cx);
18565    }
18566
18567    pub fn unfold_at(
18568        &mut self,
18569        buffer_row: MultiBufferRow,
18570        _window: &mut Window,
18571        cx: &mut Context<Self>,
18572    ) {
18573        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18574
18575        let intersection_range = Point::new(buffer_row.0, 0)
18576            ..Point::new(
18577                buffer_row.0,
18578                display_map.buffer_snapshot().line_len(buffer_row),
18579            );
18580
18581        let autoscroll = self
18582            .selections
18583            .all::<Point>(&display_map)
18584            .iter()
18585            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18586
18587        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18588    }
18589
18590    pub fn unfold_all(
18591        &mut self,
18592        _: &actions::UnfoldAll,
18593        _window: &mut Window,
18594        cx: &mut Context<Self>,
18595    ) {
18596        if self.buffer.read(cx).is_singleton() {
18597            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18598            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18599        } else {
18600            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18601                editor
18602                    .update(cx, |editor, cx| {
18603                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18604                            editor.unfold_buffer(buffer_id, cx);
18605                        }
18606                    })
18607                    .ok();
18608            });
18609        }
18610    }
18611
18612    pub fn fold_selected_ranges(
18613        &mut self,
18614        _: &FoldSelectedRanges,
18615        window: &mut Window,
18616        cx: &mut Context<Self>,
18617    ) {
18618        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18619        let selections = self.selections.all_adjusted(&display_map);
18620        let ranges = selections
18621            .into_iter()
18622            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18623            .collect::<Vec<_>>();
18624        self.fold_creases(ranges, true, window, cx);
18625    }
18626
18627    pub fn fold_ranges<T: ToOffset + Clone>(
18628        &mut self,
18629        ranges: Vec<Range<T>>,
18630        auto_scroll: bool,
18631        window: &mut Window,
18632        cx: &mut Context<Self>,
18633    ) {
18634        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18635        let ranges = ranges
18636            .into_iter()
18637            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18638            .collect::<Vec<_>>();
18639        self.fold_creases(ranges, auto_scroll, window, cx);
18640    }
18641
18642    pub fn fold_creases<T: ToOffset + Clone>(
18643        &mut self,
18644        creases: Vec<Crease<T>>,
18645        auto_scroll: bool,
18646        _window: &mut Window,
18647        cx: &mut Context<Self>,
18648    ) {
18649        if creases.is_empty() {
18650            return;
18651        }
18652
18653        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18654
18655        if auto_scroll {
18656            self.request_autoscroll(Autoscroll::fit(), cx);
18657        }
18658
18659        cx.notify();
18660
18661        self.scrollbar_marker_state.dirty = true;
18662        self.folds_did_change(cx);
18663    }
18664
18665    /// Removes any folds whose ranges intersect any of the given ranges.
18666    pub fn unfold_ranges<T: ToOffset + Clone>(
18667        &mut self,
18668        ranges: &[Range<T>],
18669        inclusive: bool,
18670        auto_scroll: bool,
18671        cx: &mut Context<Self>,
18672    ) {
18673        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18674            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18675        });
18676        self.folds_did_change(cx);
18677    }
18678
18679    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18680        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18681            return;
18682        }
18683        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18684        self.display_map.update(cx, |display_map, cx| {
18685            display_map.fold_buffers([buffer_id], cx)
18686        });
18687        cx.emit(EditorEvent::BufferFoldToggled {
18688            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18689            folded: true,
18690        });
18691        cx.notify();
18692    }
18693
18694    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18695        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18696            return;
18697        }
18698        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18699        self.display_map.update(cx, |display_map, cx| {
18700            display_map.unfold_buffers([buffer_id], cx);
18701        });
18702        cx.emit(EditorEvent::BufferFoldToggled {
18703            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18704            folded: false,
18705        });
18706        cx.notify();
18707    }
18708
18709    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18710        self.display_map.read(cx).is_buffer_folded(buffer)
18711    }
18712
18713    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18714        self.display_map.read(cx).folded_buffers()
18715    }
18716
18717    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18718        self.display_map.update(cx, |display_map, cx| {
18719            display_map.disable_header_for_buffer(buffer_id, cx);
18720        });
18721        cx.notify();
18722    }
18723
18724    /// Removes any folds with the given ranges.
18725    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18726        &mut self,
18727        ranges: &[Range<T>],
18728        type_id: TypeId,
18729        auto_scroll: bool,
18730        cx: &mut Context<Self>,
18731    ) {
18732        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18733            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18734        });
18735        self.folds_did_change(cx);
18736    }
18737
18738    fn remove_folds_with<T: ToOffset + Clone>(
18739        &mut self,
18740        ranges: &[Range<T>],
18741        auto_scroll: bool,
18742        cx: &mut Context<Self>,
18743        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18744    ) {
18745        if ranges.is_empty() {
18746            return;
18747        }
18748
18749        let mut buffers_affected = HashSet::default();
18750        let multi_buffer = self.buffer().read(cx);
18751        for range in ranges {
18752            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18753                buffers_affected.insert(buffer.read(cx).remote_id());
18754            };
18755        }
18756
18757        self.display_map.update(cx, update);
18758
18759        if auto_scroll {
18760            self.request_autoscroll(Autoscroll::fit(), cx);
18761        }
18762
18763        cx.notify();
18764        self.scrollbar_marker_state.dirty = true;
18765        self.active_indent_guides_state.dirty = true;
18766    }
18767
18768    pub fn update_renderer_widths(
18769        &mut self,
18770        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18771        cx: &mut Context<Self>,
18772    ) -> bool {
18773        self.display_map
18774            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18775    }
18776
18777    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18778        self.display_map.read(cx).fold_placeholder.clone()
18779    }
18780
18781    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18782        self.buffer.update(cx, |buffer, cx| {
18783            buffer.set_all_diff_hunks_expanded(cx);
18784        });
18785    }
18786
18787    pub fn expand_all_diff_hunks(
18788        &mut self,
18789        _: &ExpandAllDiffHunks,
18790        _window: &mut Window,
18791        cx: &mut Context<Self>,
18792    ) {
18793        self.buffer.update(cx, |buffer, cx| {
18794            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18795        });
18796    }
18797
18798    pub fn collapse_all_diff_hunks(
18799        &mut self,
18800        _: &CollapseAllDiffHunks,
18801        _window: &mut Window,
18802        cx: &mut Context<Self>,
18803    ) {
18804        self.buffer.update(cx, |buffer, cx| {
18805            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18806        });
18807    }
18808
18809    pub fn toggle_selected_diff_hunks(
18810        &mut self,
18811        _: &ToggleSelectedDiffHunks,
18812        _window: &mut Window,
18813        cx: &mut Context<Self>,
18814    ) {
18815        let ranges: Vec<_> = self
18816            .selections
18817            .disjoint_anchors()
18818            .iter()
18819            .map(|s| s.range())
18820            .collect();
18821        self.toggle_diff_hunks_in_ranges(ranges, cx);
18822    }
18823
18824    pub fn diff_hunks_in_ranges<'a>(
18825        &'a self,
18826        ranges: &'a [Range<Anchor>],
18827        buffer: &'a MultiBufferSnapshot,
18828    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18829        ranges.iter().flat_map(move |range| {
18830            let end_excerpt_id = range.end.excerpt_id;
18831            let range = range.to_point(buffer);
18832            let mut peek_end = range.end;
18833            if range.end.row < buffer.max_row().0 {
18834                peek_end = Point::new(range.end.row + 1, 0);
18835            }
18836            buffer
18837                .diff_hunks_in_range(range.start..peek_end)
18838                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18839        })
18840    }
18841
18842    pub fn has_stageable_diff_hunks_in_ranges(
18843        &self,
18844        ranges: &[Range<Anchor>],
18845        snapshot: &MultiBufferSnapshot,
18846    ) -> bool {
18847        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18848        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18849    }
18850
18851    pub fn toggle_staged_selected_diff_hunks(
18852        &mut self,
18853        _: &::git::ToggleStaged,
18854        _: &mut Window,
18855        cx: &mut Context<Self>,
18856    ) {
18857        let snapshot = self.buffer.read(cx).snapshot(cx);
18858        let ranges: Vec<_> = self
18859            .selections
18860            .disjoint_anchors()
18861            .iter()
18862            .map(|s| s.range())
18863            .collect();
18864        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18865        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18866    }
18867
18868    pub fn set_render_diff_hunk_controls(
18869        &mut self,
18870        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18871        cx: &mut Context<Self>,
18872    ) {
18873        self.render_diff_hunk_controls = render_diff_hunk_controls;
18874        cx.notify();
18875    }
18876
18877    pub fn stage_and_next(
18878        &mut self,
18879        _: &::git::StageAndNext,
18880        window: &mut Window,
18881        cx: &mut Context<Self>,
18882    ) {
18883        self.do_stage_or_unstage_and_next(true, window, cx);
18884    }
18885
18886    pub fn unstage_and_next(
18887        &mut self,
18888        _: &::git::UnstageAndNext,
18889        window: &mut Window,
18890        cx: &mut Context<Self>,
18891    ) {
18892        self.do_stage_or_unstage_and_next(false, window, cx);
18893    }
18894
18895    pub fn stage_or_unstage_diff_hunks(
18896        &mut self,
18897        stage: bool,
18898        ranges: Vec<Range<Anchor>>,
18899        cx: &mut Context<Self>,
18900    ) {
18901        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18902        cx.spawn(async move |this, cx| {
18903            task.await?;
18904            this.update(cx, |this, cx| {
18905                let snapshot = this.buffer.read(cx).snapshot(cx);
18906                let chunk_by = this
18907                    .diff_hunks_in_ranges(&ranges, &snapshot)
18908                    .chunk_by(|hunk| hunk.buffer_id);
18909                for (buffer_id, hunks) in &chunk_by {
18910                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18911                }
18912            })
18913        })
18914        .detach_and_log_err(cx);
18915    }
18916
18917    fn save_buffers_for_ranges_if_needed(
18918        &mut self,
18919        ranges: &[Range<Anchor>],
18920        cx: &mut Context<Editor>,
18921    ) -> Task<Result<()>> {
18922        let multibuffer = self.buffer.read(cx);
18923        let snapshot = multibuffer.read(cx);
18924        let buffer_ids: HashSet<_> = ranges
18925            .iter()
18926            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18927            .collect();
18928        drop(snapshot);
18929
18930        let mut buffers = HashSet::default();
18931        for buffer_id in buffer_ids {
18932            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18933                let buffer = buffer_entity.read(cx);
18934                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18935                {
18936                    buffers.insert(buffer_entity);
18937                }
18938            }
18939        }
18940
18941        if let Some(project) = &self.project {
18942            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18943        } else {
18944            Task::ready(Ok(()))
18945        }
18946    }
18947
18948    fn do_stage_or_unstage_and_next(
18949        &mut self,
18950        stage: bool,
18951        window: &mut Window,
18952        cx: &mut Context<Self>,
18953    ) {
18954        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18955
18956        if ranges.iter().any(|range| range.start != range.end) {
18957            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18958            return;
18959        }
18960
18961        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18962        let snapshot = self.snapshot(window, cx);
18963        let position = self
18964            .selections
18965            .newest::<Point>(&snapshot.display_snapshot)
18966            .head();
18967        let mut row = snapshot
18968            .buffer_snapshot()
18969            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18970            .find(|hunk| hunk.row_range.start.0 > position.row)
18971            .map(|hunk| hunk.row_range.start);
18972
18973        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18974        // Outside of the project diff editor, wrap around to the beginning.
18975        if !all_diff_hunks_expanded {
18976            row = row.or_else(|| {
18977                snapshot
18978                    .buffer_snapshot()
18979                    .diff_hunks_in_range(Point::zero()..position)
18980                    .find(|hunk| hunk.row_range.end.0 < position.row)
18981                    .map(|hunk| hunk.row_range.start)
18982            });
18983        }
18984
18985        if let Some(row) = row {
18986            let destination = Point::new(row.0, 0);
18987            let autoscroll = Autoscroll::center();
18988
18989            self.unfold_ranges(&[destination..destination], false, false, cx);
18990            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18991                s.select_ranges([destination..destination]);
18992            });
18993        }
18994    }
18995
18996    fn do_stage_or_unstage(
18997        &self,
18998        stage: bool,
18999        buffer_id: BufferId,
19000        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19001        cx: &mut App,
19002    ) -> Option<()> {
19003        let project = self.project()?;
19004        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19005        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19006        let buffer_snapshot = buffer.read(cx).snapshot();
19007        let file_exists = buffer_snapshot
19008            .file()
19009            .is_some_and(|file| file.disk_state().exists());
19010        diff.update(cx, |diff, cx| {
19011            diff.stage_or_unstage_hunks(
19012                stage,
19013                &hunks
19014                    .map(|hunk| buffer_diff::DiffHunk {
19015                        buffer_range: hunk.buffer_range,
19016                        diff_base_byte_range: hunk.diff_base_byte_range,
19017                        secondary_status: hunk.secondary_status,
19018                        range: Point::zero()..Point::zero(), // unused
19019                    })
19020                    .collect::<Vec<_>>(),
19021                &buffer_snapshot,
19022                file_exists,
19023                cx,
19024            )
19025        });
19026        None
19027    }
19028
19029    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19030        let ranges: Vec<_> = self
19031            .selections
19032            .disjoint_anchors()
19033            .iter()
19034            .map(|s| s.range())
19035            .collect();
19036        self.buffer
19037            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19038    }
19039
19040    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19041        self.buffer.update(cx, |buffer, cx| {
19042            let ranges = vec![Anchor::min()..Anchor::max()];
19043            if !buffer.all_diff_hunks_expanded()
19044                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19045            {
19046                buffer.collapse_diff_hunks(ranges, cx);
19047                true
19048            } else {
19049                false
19050            }
19051        })
19052    }
19053
19054    fn toggle_diff_hunks_in_ranges(
19055        &mut self,
19056        ranges: Vec<Range<Anchor>>,
19057        cx: &mut Context<Editor>,
19058    ) {
19059        self.buffer.update(cx, |buffer, cx| {
19060            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19061            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19062        })
19063    }
19064
19065    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19066        self.buffer.update(cx, |buffer, cx| {
19067            let snapshot = buffer.snapshot(cx);
19068            let excerpt_id = range.end.excerpt_id;
19069            let point_range = range.to_point(&snapshot);
19070            let expand = !buffer.single_hunk_is_expanded(range, cx);
19071            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19072        })
19073    }
19074
19075    pub(crate) fn apply_all_diff_hunks(
19076        &mut self,
19077        _: &ApplyAllDiffHunks,
19078        window: &mut Window,
19079        cx: &mut Context<Self>,
19080    ) {
19081        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19082
19083        let buffers = self.buffer.read(cx).all_buffers();
19084        for branch_buffer in buffers {
19085            branch_buffer.update(cx, |branch_buffer, cx| {
19086                branch_buffer.merge_into_base(Vec::new(), cx);
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(crate) fn apply_selected_diff_hunks(
19105        &mut self,
19106        _: &ApplyDiffHunk,
19107        window: &mut Window,
19108        cx: &mut Context<Self>,
19109    ) {
19110        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19111        let snapshot = self.snapshot(window, cx);
19112        let hunks = snapshot.hunks_for_ranges(
19113            self.selections
19114                .all(&snapshot.display_snapshot)
19115                .into_iter()
19116                .map(|selection| selection.range()),
19117        );
19118        let mut ranges_by_buffer = HashMap::default();
19119        self.transact(window, cx, |editor, _window, cx| {
19120            for hunk in hunks {
19121                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19122                    ranges_by_buffer
19123                        .entry(buffer.clone())
19124                        .or_insert_with(Vec::new)
19125                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19126                }
19127            }
19128
19129            for (buffer, ranges) in ranges_by_buffer {
19130                buffer.update(cx, |buffer, cx| {
19131                    buffer.merge_into_base(ranges, cx);
19132                });
19133            }
19134        });
19135
19136        if let Some(project) = self.project.clone() {
19137            self.save(
19138                SaveOptions {
19139                    format: true,
19140                    autosave: false,
19141                },
19142                project,
19143                window,
19144                cx,
19145            )
19146            .detach_and_log_err(cx);
19147        }
19148    }
19149
19150    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19151        if hovered != self.gutter_hovered {
19152            self.gutter_hovered = hovered;
19153            cx.notify();
19154        }
19155    }
19156
19157    pub fn insert_blocks(
19158        &mut self,
19159        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19160        autoscroll: Option<Autoscroll>,
19161        cx: &mut Context<Self>,
19162    ) -> Vec<CustomBlockId> {
19163        let blocks = self
19164            .display_map
19165            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19166        if let Some(autoscroll) = autoscroll {
19167            self.request_autoscroll(autoscroll, cx);
19168        }
19169        cx.notify();
19170        blocks
19171    }
19172
19173    pub fn resize_blocks(
19174        &mut self,
19175        heights: HashMap<CustomBlockId, u32>,
19176        autoscroll: Option<Autoscroll>,
19177        cx: &mut Context<Self>,
19178    ) {
19179        self.display_map
19180            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19181        if let Some(autoscroll) = autoscroll {
19182            self.request_autoscroll(autoscroll, cx);
19183        }
19184        cx.notify();
19185    }
19186
19187    pub fn replace_blocks(
19188        &mut self,
19189        renderers: HashMap<CustomBlockId, RenderBlock>,
19190        autoscroll: Option<Autoscroll>,
19191        cx: &mut Context<Self>,
19192    ) {
19193        self.display_map
19194            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19195        if let Some(autoscroll) = autoscroll {
19196            self.request_autoscroll(autoscroll, cx);
19197        }
19198        cx.notify();
19199    }
19200
19201    pub fn remove_blocks(
19202        &mut self,
19203        block_ids: HashSet<CustomBlockId>,
19204        autoscroll: Option<Autoscroll>,
19205        cx: &mut Context<Self>,
19206    ) {
19207        self.display_map.update(cx, |display_map, cx| {
19208            display_map.remove_blocks(block_ids, cx)
19209        });
19210        if let Some(autoscroll) = autoscroll {
19211            self.request_autoscroll(autoscroll, cx);
19212        }
19213        cx.notify();
19214    }
19215
19216    pub fn row_for_block(
19217        &self,
19218        block_id: CustomBlockId,
19219        cx: &mut Context<Self>,
19220    ) -> Option<DisplayRow> {
19221        self.display_map
19222            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19223    }
19224
19225    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19226        self.focused_block = Some(focused_block);
19227    }
19228
19229    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19230        self.focused_block.take()
19231    }
19232
19233    pub fn insert_creases(
19234        &mut self,
19235        creases: impl IntoIterator<Item = Crease<Anchor>>,
19236        cx: &mut Context<Self>,
19237    ) -> Vec<CreaseId> {
19238        self.display_map
19239            .update(cx, |map, cx| map.insert_creases(creases, cx))
19240    }
19241
19242    pub fn remove_creases(
19243        &mut self,
19244        ids: impl IntoIterator<Item = CreaseId>,
19245        cx: &mut Context<Self>,
19246    ) -> Vec<(CreaseId, Range<Anchor>)> {
19247        self.display_map
19248            .update(cx, |map, cx| map.remove_creases(ids, cx))
19249    }
19250
19251    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19252        self.display_map
19253            .update(cx, |map, cx| map.snapshot(cx))
19254            .longest_row()
19255    }
19256
19257    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19258        self.display_map
19259            .update(cx, |map, cx| map.snapshot(cx))
19260            .max_point()
19261    }
19262
19263    pub fn text(&self, cx: &App) -> String {
19264        self.buffer.read(cx).read(cx).text()
19265    }
19266
19267    pub fn is_empty(&self, cx: &App) -> bool {
19268        self.buffer.read(cx).read(cx).is_empty()
19269    }
19270
19271    pub fn text_option(&self, cx: &App) -> Option<String> {
19272        let text = self.text(cx);
19273        let text = text.trim();
19274
19275        if text.is_empty() {
19276            return None;
19277        }
19278
19279        Some(text.to_string())
19280    }
19281
19282    pub fn set_text(
19283        &mut self,
19284        text: impl Into<Arc<str>>,
19285        window: &mut Window,
19286        cx: &mut Context<Self>,
19287    ) {
19288        self.transact(window, cx, |this, _, cx| {
19289            this.buffer
19290                .read(cx)
19291                .as_singleton()
19292                .expect("you can only call set_text on editors for singleton buffers")
19293                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19294        });
19295    }
19296
19297    pub fn display_text(&self, cx: &mut App) -> String {
19298        self.display_map
19299            .update(cx, |map, cx| map.snapshot(cx))
19300            .text()
19301    }
19302
19303    fn create_minimap(
19304        &self,
19305        minimap_settings: MinimapSettings,
19306        window: &mut Window,
19307        cx: &mut Context<Self>,
19308    ) -> Option<Entity<Self>> {
19309        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19310            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19311    }
19312
19313    fn initialize_new_minimap(
19314        &self,
19315        minimap_settings: MinimapSettings,
19316        window: &mut Window,
19317        cx: &mut Context<Self>,
19318    ) -> Entity<Self> {
19319        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19320
19321        let mut minimap = Editor::new_internal(
19322            EditorMode::Minimap {
19323                parent: cx.weak_entity(),
19324            },
19325            self.buffer.clone(),
19326            None,
19327            Some(self.display_map.clone()),
19328            window,
19329            cx,
19330        );
19331        minimap.scroll_manager.clone_state(&self.scroll_manager);
19332        minimap.set_text_style_refinement(TextStyleRefinement {
19333            font_size: Some(MINIMAP_FONT_SIZE),
19334            font_weight: Some(MINIMAP_FONT_WEIGHT),
19335            ..Default::default()
19336        });
19337        minimap.update_minimap_configuration(minimap_settings, cx);
19338        cx.new(|_| minimap)
19339    }
19340
19341    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19342        let current_line_highlight = minimap_settings
19343            .current_line_highlight
19344            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19345        self.set_current_line_highlight(Some(current_line_highlight));
19346    }
19347
19348    pub fn minimap(&self) -> Option<&Entity<Self>> {
19349        self.minimap
19350            .as_ref()
19351            .filter(|_| self.minimap_visibility.visible())
19352    }
19353
19354    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19355        let mut wrap_guides = smallvec![];
19356
19357        if self.show_wrap_guides == Some(false) {
19358            return wrap_guides;
19359        }
19360
19361        let settings = self.buffer.read(cx).language_settings(cx);
19362        if settings.show_wrap_guides {
19363            match self.soft_wrap_mode(cx) {
19364                SoftWrap::Column(soft_wrap) => {
19365                    wrap_guides.push((soft_wrap as usize, true));
19366                }
19367                SoftWrap::Bounded(soft_wrap) => {
19368                    wrap_guides.push((soft_wrap as usize, true));
19369                }
19370                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19371            }
19372            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19373        }
19374
19375        wrap_guides
19376    }
19377
19378    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19379        let settings = self.buffer.read(cx).language_settings(cx);
19380        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19381        match mode {
19382            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19383                SoftWrap::None
19384            }
19385            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19386            language_settings::SoftWrap::PreferredLineLength => {
19387                SoftWrap::Column(settings.preferred_line_length)
19388            }
19389            language_settings::SoftWrap::Bounded => {
19390                SoftWrap::Bounded(settings.preferred_line_length)
19391            }
19392        }
19393    }
19394
19395    pub fn set_soft_wrap_mode(
19396        &mut self,
19397        mode: language_settings::SoftWrap,
19398
19399        cx: &mut Context<Self>,
19400    ) {
19401        self.soft_wrap_mode_override = Some(mode);
19402        cx.notify();
19403    }
19404
19405    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19406        self.hard_wrap = hard_wrap;
19407        cx.notify();
19408    }
19409
19410    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19411        self.text_style_refinement = Some(style);
19412    }
19413
19414    /// called by the Element so we know what style we were most recently rendered with.
19415    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19416        // We intentionally do not inform the display map about the minimap style
19417        // so that wrapping is not recalculated and stays consistent for the editor
19418        // and its linked minimap.
19419        if !self.mode.is_minimap() {
19420            let font = style.text.font();
19421            let font_size = style.text.font_size.to_pixels(window.rem_size());
19422            let display_map = self
19423                .placeholder_display_map
19424                .as_ref()
19425                .filter(|_| self.is_empty(cx))
19426                .unwrap_or(&self.display_map);
19427
19428            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19429        }
19430        self.style = Some(style);
19431    }
19432
19433    pub fn style(&self) -> Option<&EditorStyle> {
19434        self.style.as_ref()
19435    }
19436
19437    // Called by the element. This method is not designed to be called outside of the editor
19438    // element's layout code because it does not notify when rewrapping is computed synchronously.
19439    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19440        if self.is_empty(cx) {
19441            self.placeholder_display_map
19442                .as_ref()
19443                .map_or(false, |display_map| {
19444                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19445                })
19446        } else {
19447            self.display_map
19448                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19449        }
19450    }
19451
19452    pub fn set_soft_wrap(&mut self) {
19453        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19454    }
19455
19456    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19457        if self.soft_wrap_mode_override.is_some() {
19458            self.soft_wrap_mode_override.take();
19459        } else {
19460            let soft_wrap = match self.soft_wrap_mode(cx) {
19461                SoftWrap::GitDiff => return,
19462                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19463                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19464                    language_settings::SoftWrap::None
19465                }
19466            };
19467            self.soft_wrap_mode_override = Some(soft_wrap);
19468        }
19469        cx.notify();
19470    }
19471
19472    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19473        let Some(workspace) = self.workspace() else {
19474            return;
19475        };
19476        let fs = workspace.read(cx).app_state().fs.clone();
19477        let current_show = TabBarSettings::get_global(cx).show;
19478        update_settings_file(fs, cx, move |setting, _| {
19479            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19480        });
19481    }
19482
19483    pub fn toggle_indent_guides(
19484        &mut self,
19485        _: &ToggleIndentGuides,
19486        _: &mut Window,
19487        cx: &mut Context<Self>,
19488    ) {
19489        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19490            self.buffer
19491                .read(cx)
19492                .language_settings(cx)
19493                .indent_guides
19494                .enabled
19495        });
19496        self.show_indent_guides = Some(!currently_enabled);
19497        cx.notify();
19498    }
19499
19500    fn should_show_indent_guides(&self) -> Option<bool> {
19501        self.show_indent_guides
19502    }
19503
19504    pub fn toggle_line_numbers(
19505        &mut self,
19506        _: &ToggleLineNumbers,
19507        _: &mut Window,
19508        cx: &mut Context<Self>,
19509    ) {
19510        let mut editor_settings = EditorSettings::get_global(cx).clone();
19511        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19512        EditorSettings::override_global(editor_settings, cx);
19513    }
19514
19515    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19516        if let Some(show_line_numbers) = self.show_line_numbers {
19517            return show_line_numbers;
19518        }
19519        EditorSettings::get_global(cx).gutter.line_numbers
19520    }
19521
19522    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19523        match (
19524            self.use_relative_line_numbers,
19525            EditorSettings::get_global(cx).relative_line_numbers,
19526        ) {
19527            (None, setting) => setting,
19528            (Some(false), _) => RelativeLineNumbers::Disabled,
19529            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19530            (Some(true), _) => RelativeLineNumbers::Enabled,
19531        }
19532    }
19533
19534    pub fn toggle_relative_line_numbers(
19535        &mut self,
19536        _: &ToggleRelativeLineNumbers,
19537        _: &mut Window,
19538        cx: &mut Context<Self>,
19539    ) {
19540        let is_relative = self.relative_line_numbers(cx);
19541        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19542    }
19543
19544    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19545        self.use_relative_line_numbers = is_relative;
19546        cx.notify();
19547    }
19548
19549    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19550        self.show_gutter = show_gutter;
19551        cx.notify();
19552    }
19553
19554    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19555        self.show_scrollbars = ScrollbarAxes {
19556            horizontal: show,
19557            vertical: show,
19558        };
19559        cx.notify();
19560    }
19561
19562    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19563        self.show_scrollbars.vertical = show;
19564        cx.notify();
19565    }
19566
19567    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19568        self.show_scrollbars.horizontal = show;
19569        cx.notify();
19570    }
19571
19572    pub fn set_minimap_visibility(
19573        &mut self,
19574        minimap_visibility: MinimapVisibility,
19575        window: &mut Window,
19576        cx: &mut Context<Self>,
19577    ) {
19578        if self.minimap_visibility != minimap_visibility {
19579            if minimap_visibility.visible() && self.minimap.is_none() {
19580                let minimap_settings = EditorSettings::get_global(cx).minimap;
19581                self.minimap =
19582                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19583            }
19584            self.minimap_visibility = minimap_visibility;
19585            cx.notify();
19586        }
19587    }
19588
19589    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19590        self.set_show_scrollbars(false, cx);
19591        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19592    }
19593
19594    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19595        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19596    }
19597
19598    /// Normally the text in full mode and auto height editors is padded on the
19599    /// left side by roughly half a character width for improved hit testing.
19600    ///
19601    /// Use this method to disable this for cases where this is not wanted (e.g.
19602    /// if you want to align the editor text with some other text above or below)
19603    /// or if you want to add this padding to single-line editors.
19604    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19605        self.offset_content = offset_content;
19606        cx.notify();
19607    }
19608
19609    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19610        self.show_line_numbers = Some(show_line_numbers);
19611        cx.notify();
19612    }
19613
19614    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19615        self.disable_expand_excerpt_buttons = true;
19616        cx.notify();
19617    }
19618
19619    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19620        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19621        cx.notify();
19622    }
19623
19624    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19625        self.show_code_actions = Some(show_code_actions);
19626        cx.notify();
19627    }
19628
19629    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19630        self.show_runnables = Some(show_runnables);
19631        cx.notify();
19632    }
19633
19634    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19635        self.show_breakpoints = Some(show_breakpoints);
19636        cx.notify();
19637    }
19638
19639    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19640        if self.display_map.read(cx).masked != masked {
19641            self.display_map.update(cx, |map, _| map.masked = masked);
19642        }
19643        cx.notify()
19644    }
19645
19646    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19647        self.show_wrap_guides = Some(show_wrap_guides);
19648        cx.notify();
19649    }
19650
19651    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19652        self.show_indent_guides = Some(show_indent_guides);
19653        cx.notify();
19654    }
19655
19656    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19657        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19658            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19659                && let Some(dir) = file.abs_path(cx).parent()
19660            {
19661                return Some(dir.to_owned());
19662            }
19663        }
19664
19665        None
19666    }
19667
19668    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19669        self.active_excerpt(cx)?
19670            .1
19671            .read(cx)
19672            .file()
19673            .and_then(|f| f.as_local())
19674    }
19675
19676    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19677        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19678            let buffer = buffer.read(cx);
19679            if let Some(project_path) = buffer.project_path(cx) {
19680                let project = self.project()?.read(cx);
19681                project.absolute_path(&project_path, cx)
19682            } else {
19683                buffer
19684                    .file()
19685                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19686            }
19687        })
19688    }
19689
19690    pub fn reveal_in_finder(
19691        &mut self,
19692        _: &RevealInFileManager,
19693        _window: &mut Window,
19694        cx: &mut Context<Self>,
19695    ) {
19696        if let Some(target) = self.target_file(cx) {
19697            cx.reveal_path(&target.abs_path(cx));
19698        }
19699    }
19700
19701    pub fn copy_path(
19702        &mut self,
19703        _: &zed_actions::workspace::CopyPath,
19704        _window: &mut Window,
19705        cx: &mut Context<Self>,
19706    ) {
19707        if let Some(path) = self.target_file_abs_path(cx)
19708            && let Some(path) = path.to_str()
19709        {
19710            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19711        } else {
19712            cx.propagate();
19713        }
19714    }
19715
19716    pub fn copy_relative_path(
19717        &mut self,
19718        _: &zed_actions::workspace::CopyRelativePath,
19719        _window: &mut Window,
19720        cx: &mut Context<Self>,
19721    ) {
19722        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19723            let project = self.project()?.read(cx);
19724            let path = buffer.read(cx).file()?.path();
19725            let path = path.display(project.path_style(cx));
19726            Some(path)
19727        }) {
19728            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19729        } else {
19730            cx.propagate();
19731        }
19732    }
19733
19734    /// Returns the project path for the editor's buffer, if any buffer is
19735    /// opened in the editor.
19736    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19737        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19738            buffer.read(cx).project_path(cx)
19739        } else {
19740            None
19741        }
19742    }
19743
19744    // Returns true if the editor handled a go-to-line request
19745    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19746        maybe!({
19747            let breakpoint_store = self.breakpoint_store.as_ref()?;
19748
19749            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19750            else {
19751                self.clear_row_highlights::<ActiveDebugLine>();
19752                return None;
19753            };
19754
19755            let position = active_stack_frame.position;
19756            let buffer_id = position.buffer_id?;
19757            let snapshot = self
19758                .project
19759                .as_ref()?
19760                .read(cx)
19761                .buffer_for_id(buffer_id, cx)?
19762                .read(cx)
19763                .snapshot();
19764
19765            let mut handled = false;
19766            for (id, ExcerptRange { context, .. }) in
19767                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19768            {
19769                if context.start.cmp(&position, &snapshot).is_ge()
19770                    || context.end.cmp(&position, &snapshot).is_lt()
19771                {
19772                    continue;
19773                }
19774                let snapshot = self.buffer.read(cx).snapshot(cx);
19775                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19776
19777                handled = true;
19778                self.clear_row_highlights::<ActiveDebugLine>();
19779
19780                self.go_to_line::<ActiveDebugLine>(
19781                    multibuffer_anchor,
19782                    Some(cx.theme().colors().editor_debugger_active_line_background),
19783                    window,
19784                    cx,
19785                );
19786
19787                cx.notify();
19788            }
19789
19790            handled.then_some(())
19791        })
19792        .is_some()
19793    }
19794
19795    pub fn copy_file_name_without_extension(
19796        &mut self,
19797        _: &CopyFileNameWithoutExtension,
19798        _: &mut Window,
19799        cx: &mut Context<Self>,
19800    ) {
19801        if let Some(file) = self.target_file(cx)
19802            && let Some(file_stem) = file.path().file_stem()
19803        {
19804            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19805        }
19806    }
19807
19808    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19809        if let Some(file) = self.target_file(cx)
19810            && let Some(name) = file.path().file_name()
19811        {
19812            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19813        }
19814    }
19815
19816    pub fn toggle_git_blame(
19817        &mut self,
19818        _: &::git::Blame,
19819        window: &mut Window,
19820        cx: &mut Context<Self>,
19821    ) {
19822        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19823
19824        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19825            self.start_git_blame(true, window, cx);
19826        }
19827
19828        cx.notify();
19829    }
19830
19831    pub fn toggle_git_blame_inline(
19832        &mut self,
19833        _: &ToggleGitBlameInline,
19834        window: &mut Window,
19835        cx: &mut Context<Self>,
19836    ) {
19837        self.toggle_git_blame_inline_internal(true, window, cx);
19838        cx.notify();
19839    }
19840
19841    pub fn open_git_blame_commit(
19842        &mut self,
19843        _: &OpenGitBlameCommit,
19844        window: &mut Window,
19845        cx: &mut Context<Self>,
19846    ) {
19847        self.open_git_blame_commit_internal(window, cx);
19848    }
19849
19850    fn open_git_blame_commit_internal(
19851        &mut self,
19852        window: &mut Window,
19853        cx: &mut Context<Self>,
19854    ) -> Option<()> {
19855        let blame = self.blame.as_ref()?;
19856        let snapshot = self.snapshot(window, cx);
19857        let cursor = self
19858            .selections
19859            .newest::<Point>(&snapshot.display_snapshot)
19860            .head();
19861        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19862        let (_, blame_entry) = blame
19863            .update(cx, |blame, cx| {
19864                blame
19865                    .blame_for_rows(
19866                        &[RowInfo {
19867                            buffer_id: Some(buffer.remote_id()),
19868                            buffer_row: Some(point.row),
19869                            ..Default::default()
19870                        }],
19871                        cx,
19872                    )
19873                    .next()
19874            })
19875            .flatten()?;
19876        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19877        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19878        let workspace = self.workspace()?.downgrade();
19879        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19880        None
19881    }
19882
19883    pub fn git_blame_inline_enabled(&self) -> bool {
19884        self.git_blame_inline_enabled
19885    }
19886
19887    pub fn toggle_selection_menu(
19888        &mut self,
19889        _: &ToggleSelectionMenu,
19890        _: &mut Window,
19891        cx: &mut Context<Self>,
19892    ) {
19893        self.show_selection_menu = self
19894            .show_selection_menu
19895            .map(|show_selections_menu| !show_selections_menu)
19896            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19897
19898        cx.notify();
19899    }
19900
19901    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19902        self.show_selection_menu
19903            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19904    }
19905
19906    fn start_git_blame(
19907        &mut self,
19908        user_triggered: bool,
19909        window: &mut Window,
19910        cx: &mut Context<Self>,
19911    ) {
19912        if let Some(project) = self.project() {
19913            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19914                && buffer.read(cx).file().is_none()
19915            {
19916                return;
19917            }
19918
19919            let focused = self.focus_handle(cx).contains_focused(window, cx);
19920
19921            let project = project.clone();
19922            let blame = cx
19923                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19924            self.blame_subscription =
19925                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19926            self.blame = Some(blame);
19927        }
19928    }
19929
19930    fn toggle_git_blame_inline_internal(
19931        &mut self,
19932        user_triggered: bool,
19933        window: &mut Window,
19934        cx: &mut Context<Self>,
19935    ) {
19936        if self.git_blame_inline_enabled {
19937            self.git_blame_inline_enabled = false;
19938            self.show_git_blame_inline = false;
19939            self.show_git_blame_inline_delay_task.take();
19940        } else {
19941            self.git_blame_inline_enabled = true;
19942            self.start_git_blame_inline(user_triggered, window, cx);
19943        }
19944
19945        cx.notify();
19946    }
19947
19948    fn start_git_blame_inline(
19949        &mut self,
19950        user_triggered: bool,
19951        window: &mut Window,
19952        cx: &mut Context<Self>,
19953    ) {
19954        self.start_git_blame(user_triggered, window, cx);
19955
19956        if ProjectSettings::get_global(cx)
19957            .git
19958            .inline_blame_delay()
19959            .is_some()
19960        {
19961            self.start_inline_blame_timer(window, cx);
19962        } else {
19963            self.show_git_blame_inline = true
19964        }
19965    }
19966
19967    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19968        self.blame.as_ref()
19969    }
19970
19971    pub fn show_git_blame_gutter(&self) -> bool {
19972        self.show_git_blame_gutter
19973    }
19974
19975    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19976        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19977    }
19978
19979    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19980        self.show_git_blame_inline
19981            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19982            && !self.newest_selection_head_on_empty_line(cx)
19983            && self.has_blame_entries(cx)
19984    }
19985
19986    fn has_blame_entries(&self, cx: &App) -> bool {
19987        self.blame()
19988            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19989    }
19990
19991    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19992        let cursor_anchor = self.selections.newest_anchor().head();
19993
19994        let snapshot = self.buffer.read(cx).snapshot(cx);
19995        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19996
19997        snapshot.line_len(buffer_row) == 0
19998    }
19999
20000    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20001        let buffer_and_selection = maybe!({
20002            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20003            let selection_range = selection.range();
20004
20005            let multi_buffer = self.buffer().read(cx);
20006            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20007            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20008
20009            let (buffer, range, _) = if selection.reversed {
20010                buffer_ranges.first()
20011            } else {
20012                buffer_ranges.last()
20013            }?;
20014
20015            let selection = text::ToPoint::to_point(&range.start, buffer).row
20016                ..text::ToPoint::to_point(&range.end, buffer).row;
20017            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20018        });
20019
20020        let Some((buffer, selection)) = buffer_and_selection else {
20021            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20022        };
20023
20024        let Some(project) = self.project() else {
20025            return Task::ready(Err(anyhow!("editor does not have project")));
20026        };
20027
20028        project.update(cx, |project, cx| {
20029            project.get_permalink_to_line(&buffer, selection, cx)
20030        })
20031    }
20032
20033    pub fn copy_permalink_to_line(
20034        &mut self,
20035        _: &CopyPermalinkToLine,
20036        window: &mut Window,
20037        cx: &mut Context<Self>,
20038    ) {
20039        let permalink_task = self.get_permalink_to_line(cx);
20040        let workspace = self.workspace();
20041
20042        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20043            Ok(permalink) => {
20044                cx.update(|_, cx| {
20045                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20046                })
20047                .ok();
20048            }
20049            Err(err) => {
20050                let message = format!("Failed to copy permalink: {err}");
20051
20052                anyhow::Result::<()>::Err(err).log_err();
20053
20054                if let Some(workspace) = workspace {
20055                    workspace
20056                        .update_in(cx, |workspace, _, cx| {
20057                            struct CopyPermalinkToLine;
20058
20059                            workspace.show_toast(
20060                                Toast::new(
20061                                    NotificationId::unique::<CopyPermalinkToLine>(),
20062                                    message,
20063                                ),
20064                                cx,
20065                            )
20066                        })
20067                        .ok();
20068                }
20069            }
20070        })
20071        .detach();
20072    }
20073
20074    pub fn copy_file_location(
20075        &mut self,
20076        _: &CopyFileLocation,
20077        _: &mut Window,
20078        cx: &mut Context<Self>,
20079    ) {
20080        let selection = self
20081            .selections
20082            .newest::<Point>(&self.display_snapshot(cx))
20083            .start
20084            .row
20085            + 1;
20086        if let Some(file) = self.target_file(cx) {
20087            let path = file.path().display(file.path_style(cx));
20088            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20089        }
20090    }
20091
20092    pub fn open_permalink_to_line(
20093        &mut self,
20094        _: &OpenPermalinkToLine,
20095        window: &mut Window,
20096        cx: &mut Context<Self>,
20097    ) {
20098        let permalink_task = self.get_permalink_to_line(cx);
20099        let workspace = self.workspace();
20100
20101        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20102            Ok(permalink) => {
20103                cx.update(|_, cx| {
20104                    cx.open_url(permalink.as_ref());
20105                })
20106                .ok();
20107            }
20108            Err(err) => {
20109                let message = format!("Failed to open permalink: {err}");
20110
20111                anyhow::Result::<()>::Err(err).log_err();
20112
20113                if let Some(workspace) = workspace {
20114                    workspace
20115                        .update(cx, |workspace, cx| {
20116                            struct OpenPermalinkToLine;
20117
20118                            workspace.show_toast(
20119                                Toast::new(
20120                                    NotificationId::unique::<OpenPermalinkToLine>(),
20121                                    message,
20122                                ),
20123                                cx,
20124                            )
20125                        })
20126                        .ok();
20127                }
20128            }
20129        })
20130        .detach();
20131    }
20132
20133    pub fn insert_uuid_v4(
20134        &mut self,
20135        _: &InsertUuidV4,
20136        window: &mut Window,
20137        cx: &mut Context<Self>,
20138    ) {
20139        self.insert_uuid(UuidVersion::V4, window, cx);
20140    }
20141
20142    pub fn insert_uuid_v7(
20143        &mut self,
20144        _: &InsertUuidV7,
20145        window: &mut Window,
20146        cx: &mut Context<Self>,
20147    ) {
20148        self.insert_uuid(UuidVersion::V7, window, cx);
20149    }
20150
20151    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20152        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20153        self.transact(window, cx, |this, window, cx| {
20154            let edits = this
20155                .selections
20156                .all::<Point>(&this.display_snapshot(cx))
20157                .into_iter()
20158                .map(|selection| {
20159                    let uuid = match version {
20160                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20161                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20162                    };
20163
20164                    (selection.range(), uuid.to_string())
20165                });
20166            this.edit(edits, cx);
20167            this.refresh_edit_prediction(true, false, window, cx);
20168        });
20169    }
20170
20171    pub fn open_selections_in_multibuffer(
20172        &mut self,
20173        _: &OpenSelectionsInMultibuffer,
20174        window: &mut Window,
20175        cx: &mut Context<Self>,
20176    ) {
20177        let multibuffer = self.buffer.read(cx);
20178
20179        let Some(buffer) = multibuffer.as_singleton() else {
20180            return;
20181        };
20182
20183        let Some(workspace) = self.workspace() else {
20184            return;
20185        };
20186
20187        let title = multibuffer.title(cx).to_string();
20188
20189        let locations = self
20190            .selections
20191            .all_anchors(cx)
20192            .iter()
20193            .map(|selection| {
20194                (
20195                    buffer.clone(),
20196                    (selection.start.text_anchor..selection.end.text_anchor)
20197                        .to_point(buffer.read(cx)),
20198                )
20199            })
20200            .into_group_map();
20201
20202        cx.spawn_in(window, async move |_, cx| {
20203            workspace.update_in(cx, |workspace, window, cx| {
20204                Self::open_locations_in_multibuffer(
20205                    workspace,
20206                    locations,
20207                    format!("Selections for '{title}'"),
20208                    false,
20209                    MultibufferSelectionMode::All,
20210                    window,
20211                    cx,
20212                );
20213            })
20214        })
20215        .detach();
20216    }
20217
20218    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20219    /// last highlight added will be used.
20220    ///
20221    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20222    pub fn highlight_rows<T: 'static>(
20223        &mut self,
20224        range: Range<Anchor>,
20225        color: Hsla,
20226        options: RowHighlightOptions,
20227        cx: &mut Context<Self>,
20228    ) {
20229        let snapshot = self.buffer().read(cx).snapshot(cx);
20230        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20231        let ix = row_highlights.binary_search_by(|highlight| {
20232            Ordering::Equal
20233                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20234                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20235        });
20236
20237        if let Err(mut ix) = ix {
20238            let index = post_inc(&mut self.highlight_order);
20239
20240            // If this range intersects with the preceding highlight, then merge it with
20241            // the preceding highlight. Otherwise insert a new highlight.
20242            let mut merged = false;
20243            if ix > 0 {
20244                let prev_highlight = &mut row_highlights[ix - 1];
20245                if prev_highlight
20246                    .range
20247                    .end
20248                    .cmp(&range.start, &snapshot)
20249                    .is_ge()
20250                {
20251                    ix -= 1;
20252                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20253                        prev_highlight.range.end = range.end;
20254                    }
20255                    merged = true;
20256                    prev_highlight.index = index;
20257                    prev_highlight.color = color;
20258                    prev_highlight.options = options;
20259                }
20260            }
20261
20262            if !merged {
20263                row_highlights.insert(
20264                    ix,
20265                    RowHighlight {
20266                        range,
20267                        index,
20268                        color,
20269                        options,
20270                        type_id: TypeId::of::<T>(),
20271                    },
20272                );
20273            }
20274
20275            // If any of the following highlights intersect with this one, merge them.
20276            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20277                let highlight = &row_highlights[ix];
20278                if next_highlight
20279                    .range
20280                    .start
20281                    .cmp(&highlight.range.end, &snapshot)
20282                    .is_le()
20283                {
20284                    if next_highlight
20285                        .range
20286                        .end
20287                        .cmp(&highlight.range.end, &snapshot)
20288                        .is_gt()
20289                    {
20290                        row_highlights[ix].range.end = next_highlight.range.end;
20291                    }
20292                    row_highlights.remove(ix + 1);
20293                } else {
20294                    break;
20295                }
20296            }
20297        }
20298    }
20299
20300    /// Remove any highlighted row ranges of the given type that intersect the
20301    /// given ranges.
20302    pub fn remove_highlighted_rows<T: 'static>(
20303        &mut self,
20304        ranges_to_remove: Vec<Range<Anchor>>,
20305        cx: &mut Context<Self>,
20306    ) {
20307        let snapshot = self.buffer().read(cx).snapshot(cx);
20308        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20309        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20310        row_highlights.retain(|highlight| {
20311            while let Some(range_to_remove) = ranges_to_remove.peek() {
20312                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20313                    Ordering::Less | Ordering::Equal => {
20314                        ranges_to_remove.next();
20315                    }
20316                    Ordering::Greater => {
20317                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20318                            Ordering::Less | Ordering::Equal => {
20319                                return false;
20320                            }
20321                            Ordering::Greater => break,
20322                        }
20323                    }
20324                }
20325            }
20326
20327            true
20328        })
20329    }
20330
20331    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20332    pub fn clear_row_highlights<T: 'static>(&mut self) {
20333        self.highlighted_rows.remove(&TypeId::of::<T>());
20334    }
20335
20336    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20337    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20338        self.highlighted_rows
20339            .get(&TypeId::of::<T>())
20340            .map_or(&[] as &[_], |vec| vec.as_slice())
20341            .iter()
20342            .map(|highlight| (highlight.range.clone(), highlight.color))
20343    }
20344
20345    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20346    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20347    /// Allows to ignore certain kinds of highlights.
20348    pub fn highlighted_display_rows(
20349        &self,
20350        window: &mut Window,
20351        cx: &mut App,
20352    ) -> BTreeMap<DisplayRow, LineHighlight> {
20353        let snapshot = self.snapshot(window, cx);
20354        let mut used_highlight_orders = HashMap::default();
20355        self.highlighted_rows
20356            .iter()
20357            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20358            .fold(
20359                BTreeMap::<DisplayRow, LineHighlight>::new(),
20360                |mut unique_rows, highlight| {
20361                    let start = highlight.range.start.to_display_point(&snapshot);
20362                    let end = highlight.range.end.to_display_point(&snapshot);
20363                    let start_row = start.row().0;
20364                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20365                        && end.column() == 0
20366                    {
20367                        end.row().0.saturating_sub(1)
20368                    } else {
20369                        end.row().0
20370                    };
20371                    for row in start_row..=end_row {
20372                        let used_index =
20373                            used_highlight_orders.entry(row).or_insert(highlight.index);
20374                        if highlight.index >= *used_index {
20375                            *used_index = highlight.index;
20376                            unique_rows.insert(
20377                                DisplayRow(row),
20378                                LineHighlight {
20379                                    include_gutter: highlight.options.include_gutter,
20380                                    border: None,
20381                                    background: highlight.color.into(),
20382                                    type_id: Some(highlight.type_id),
20383                                },
20384                            );
20385                        }
20386                    }
20387                    unique_rows
20388                },
20389            )
20390    }
20391
20392    pub fn highlighted_display_row_for_autoscroll(
20393        &self,
20394        snapshot: &DisplaySnapshot,
20395    ) -> Option<DisplayRow> {
20396        self.highlighted_rows
20397            .values()
20398            .flat_map(|highlighted_rows| highlighted_rows.iter())
20399            .filter_map(|highlight| {
20400                if highlight.options.autoscroll {
20401                    Some(highlight.range.start.to_display_point(snapshot).row())
20402                } else {
20403                    None
20404                }
20405            })
20406            .min()
20407    }
20408
20409    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20410        self.highlight_background::<SearchWithinRange>(
20411            ranges,
20412            |colors| colors.colors().editor_document_highlight_read_background,
20413            cx,
20414        )
20415    }
20416
20417    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20418        self.breadcrumb_header = Some(new_header);
20419    }
20420
20421    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20422        self.clear_background_highlights::<SearchWithinRange>(cx);
20423    }
20424
20425    pub fn highlight_background<T: 'static>(
20426        &mut self,
20427        ranges: &[Range<Anchor>],
20428        color_fetcher: fn(&Theme) -> Hsla,
20429        cx: &mut Context<Self>,
20430    ) {
20431        self.background_highlights.insert(
20432            HighlightKey::Type(TypeId::of::<T>()),
20433            (color_fetcher, Arc::from(ranges)),
20434        );
20435        self.scrollbar_marker_state.dirty = true;
20436        cx.notify();
20437    }
20438
20439    pub fn highlight_background_key<T: 'static>(
20440        &mut self,
20441        key: usize,
20442        ranges: &[Range<Anchor>],
20443        color_fetcher: fn(&Theme) -> Hsla,
20444        cx: &mut Context<Self>,
20445    ) {
20446        self.background_highlights.insert(
20447            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20448            (color_fetcher, Arc::from(ranges)),
20449        );
20450        self.scrollbar_marker_state.dirty = true;
20451        cx.notify();
20452    }
20453
20454    pub fn clear_background_highlights<T: 'static>(
20455        &mut self,
20456        cx: &mut Context<Self>,
20457    ) -> Option<BackgroundHighlight> {
20458        let text_highlights = self
20459            .background_highlights
20460            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20461        if !text_highlights.1.is_empty() {
20462            self.scrollbar_marker_state.dirty = true;
20463            cx.notify();
20464        }
20465        Some(text_highlights)
20466    }
20467
20468    pub fn highlight_gutter<T: 'static>(
20469        &mut self,
20470        ranges: impl Into<Vec<Range<Anchor>>>,
20471        color_fetcher: fn(&App) -> Hsla,
20472        cx: &mut Context<Self>,
20473    ) {
20474        self.gutter_highlights
20475            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20476        cx.notify();
20477    }
20478
20479    pub fn clear_gutter_highlights<T: 'static>(
20480        &mut self,
20481        cx: &mut Context<Self>,
20482    ) -> Option<GutterHighlight> {
20483        cx.notify();
20484        self.gutter_highlights.remove(&TypeId::of::<T>())
20485    }
20486
20487    pub fn insert_gutter_highlight<T: 'static>(
20488        &mut self,
20489        range: Range<Anchor>,
20490        color_fetcher: fn(&App) -> Hsla,
20491        cx: &mut Context<Self>,
20492    ) {
20493        let snapshot = self.buffer().read(cx).snapshot(cx);
20494        let mut highlights = self
20495            .gutter_highlights
20496            .remove(&TypeId::of::<T>())
20497            .map(|(_, highlights)| highlights)
20498            .unwrap_or_default();
20499        let ix = highlights.binary_search_by(|highlight| {
20500            Ordering::Equal
20501                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20502                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20503        });
20504        if let Err(ix) = ix {
20505            highlights.insert(ix, range);
20506        }
20507        self.gutter_highlights
20508            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20509    }
20510
20511    pub fn remove_gutter_highlights<T: 'static>(
20512        &mut self,
20513        ranges_to_remove: Vec<Range<Anchor>>,
20514        cx: &mut Context<Self>,
20515    ) {
20516        let snapshot = self.buffer().read(cx).snapshot(cx);
20517        let Some((color_fetcher, mut gutter_highlights)) =
20518            self.gutter_highlights.remove(&TypeId::of::<T>())
20519        else {
20520            return;
20521        };
20522        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20523        gutter_highlights.retain(|highlight| {
20524            while let Some(range_to_remove) = ranges_to_remove.peek() {
20525                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20526                    Ordering::Less | Ordering::Equal => {
20527                        ranges_to_remove.next();
20528                    }
20529                    Ordering::Greater => {
20530                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20531                            Ordering::Less | Ordering::Equal => {
20532                                return false;
20533                            }
20534                            Ordering::Greater => break,
20535                        }
20536                    }
20537                }
20538            }
20539
20540            true
20541        });
20542        self.gutter_highlights
20543            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20544    }
20545
20546    #[cfg(feature = "test-support")]
20547    pub fn all_text_highlights(
20548        &self,
20549        window: &mut Window,
20550        cx: &mut Context<Self>,
20551    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20552        let snapshot = self.snapshot(window, cx);
20553        self.display_map.update(cx, |display_map, _| {
20554            display_map
20555                .all_text_highlights()
20556                .map(|highlight| {
20557                    let (style, ranges) = highlight.as_ref();
20558                    (
20559                        *style,
20560                        ranges
20561                            .iter()
20562                            .map(|range| range.clone().to_display_points(&snapshot))
20563                            .collect(),
20564                    )
20565                })
20566                .collect()
20567        })
20568    }
20569
20570    #[cfg(feature = "test-support")]
20571    pub fn all_text_background_highlights(
20572        &self,
20573        window: &mut Window,
20574        cx: &mut Context<Self>,
20575    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20576        let snapshot = self.snapshot(window, cx);
20577        let buffer = &snapshot.buffer_snapshot();
20578        let start = buffer.anchor_before(0);
20579        let end = buffer.anchor_after(buffer.len());
20580        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20581    }
20582
20583    #[cfg(any(test, feature = "test-support"))]
20584    pub fn sorted_background_highlights_in_range(
20585        &self,
20586        search_range: Range<Anchor>,
20587        display_snapshot: &DisplaySnapshot,
20588        theme: &Theme,
20589    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20590        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20591        res.sort_by(|a, b| {
20592            a.0.start
20593                .cmp(&b.0.start)
20594                .then_with(|| a.0.end.cmp(&b.0.end))
20595                .then_with(|| a.1.cmp(&b.1))
20596        });
20597        res
20598    }
20599
20600    #[cfg(feature = "test-support")]
20601    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20602        let snapshot = self.buffer().read(cx).snapshot(cx);
20603
20604        let highlights = self
20605            .background_highlights
20606            .get(&HighlightKey::Type(TypeId::of::<
20607                items::BufferSearchHighlights,
20608            >()));
20609
20610        if let Some((_color, ranges)) = highlights {
20611            ranges
20612                .iter()
20613                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20614                .collect_vec()
20615        } else {
20616            vec![]
20617        }
20618    }
20619
20620    fn document_highlights_for_position<'a>(
20621        &'a self,
20622        position: Anchor,
20623        buffer: &'a MultiBufferSnapshot,
20624    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20625        let read_highlights = self
20626            .background_highlights
20627            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20628            .map(|h| &h.1);
20629        let write_highlights = self
20630            .background_highlights
20631            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20632            .map(|h| &h.1);
20633        let left_position = position.bias_left(buffer);
20634        let right_position = position.bias_right(buffer);
20635        read_highlights
20636            .into_iter()
20637            .chain(write_highlights)
20638            .flat_map(move |ranges| {
20639                let start_ix = match ranges.binary_search_by(|probe| {
20640                    let cmp = probe.end.cmp(&left_position, buffer);
20641                    if cmp.is_ge() {
20642                        Ordering::Greater
20643                    } else {
20644                        Ordering::Less
20645                    }
20646                }) {
20647                    Ok(i) | Err(i) => i,
20648                };
20649
20650                ranges[start_ix..]
20651                    .iter()
20652                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20653            })
20654    }
20655
20656    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20657        self.background_highlights
20658            .get(&HighlightKey::Type(TypeId::of::<T>()))
20659            .is_some_and(|(_, highlights)| !highlights.is_empty())
20660    }
20661
20662    /// Returns all background highlights for a given range.
20663    ///
20664    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20665    pub fn background_highlights_in_range(
20666        &self,
20667        search_range: Range<Anchor>,
20668        display_snapshot: &DisplaySnapshot,
20669        theme: &Theme,
20670    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20671        let mut results = Vec::new();
20672        for (color_fetcher, ranges) in self.background_highlights.values() {
20673            let color = color_fetcher(theme);
20674            let start_ix = match ranges.binary_search_by(|probe| {
20675                let cmp = probe
20676                    .end
20677                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20678                if cmp.is_gt() {
20679                    Ordering::Greater
20680                } else {
20681                    Ordering::Less
20682                }
20683            }) {
20684                Ok(i) | Err(i) => i,
20685            };
20686            for range in &ranges[start_ix..] {
20687                if range
20688                    .start
20689                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20690                    .is_ge()
20691                {
20692                    break;
20693                }
20694
20695                let start = range.start.to_display_point(display_snapshot);
20696                let end = range.end.to_display_point(display_snapshot);
20697                results.push((start..end, color))
20698            }
20699        }
20700        results
20701    }
20702
20703    pub fn gutter_highlights_in_range(
20704        &self,
20705        search_range: Range<Anchor>,
20706        display_snapshot: &DisplaySnapshot,
20707        cx: &App,
20708    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20709        let mut results = Vec::new();
20710        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20711            let color = color_fetcher(cx);
20712            let start_ix = match ranges.binary_search_by(|probe| {
20713                let cmp = probe
20714                    .end
20715                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20716                if cmp.is_gt() {
20717                    Ordering::Greater
20718                } else {
20719                    Ordering::Less
20720                }
20721            }) {
20722                Ok(i) | Err(i) => i,
20723            };
20724            for range in &ranges[start_ix..] {
20725                if range
20726                    .start
20727                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20728                    .is_ge()
20729                {
20730                    break;
20731                }
20732
20733                let start = range.start.to_display_point(display_snapshot);
20734                let end = range.end.to_display_point(display_snapshot);
20735                results.push((start..end, color))
20736            }
20737        }
20738        results
20739    }
20740
20741    /// Get the text ranges corresponding to the redaction query
20742    pub fn redacted_ranges(
20743        &self,
20744        search_range: Range<Anchor>,
20745        display_snapshot: &DisplaySnapshot,
20746        cx: &App,
20747    ) -> Vec<Range<DisplayPoint>> {
20748        display_snapshot
20749            .buffer_snapshot()
20750            .redacted_ranges(search_range, |file| {
20751                if let Some(file) = file {
20752                    file.is_private()
20753                        && EditorSettings::get(
20754                            Some(SettingsLocation {
20755                                worktree_id: file.worktree_id(cx),
20756                                path: file.path().as_ref(),
20757                            }),
20758                            cx,
20759                        )
20760                        .redact_private_values
20761                } else {
20762                    false
20763                }
20764            })
20765            .map(|range| {
20766                range.start.to_display_point(display_snapshot)
20767                    ..range.end.to_display_point(display_snapshot)
20768            })
20769            .collect()
20770    }
20771
20772    pub fn highlight_text_key<T: 'static>(
20773        &mut self,
20774        key: usize,
20775        ranges: Vec<Range<Anchor>>,
20776        style: HighlightStyle,
20777        cx: &mut Context<Self>,
20778    ) {
20779        self.display_map.update(cx, |map, _| {
20780            map.highlight_text(
20781                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20782                ranges,
20783                style,
20784            );
20785        });
20786        cx.notify();
20787    }
20788
20789    pub fn highlight_text<T: 'static>(
20790        &mut self,
20791        ranges: Vec<Range<Anchor>>,
20792        style: HighlightStyle,
20793        cx: &mut Context<Self>,
20794    ) {
20795        self.display_map.update(cx, |map, _| {
20796            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20797        });
20798        cx.notify();
20799    }
20800
20801    pub fn text_highlights<'a, T: 'static>(
20802        &'a self,
20803        cx: &'a App,
20804    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20805        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20806    }
20807
20808    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20809        let cleared = self
20810            .display_map
20811            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20812        if cleared {
20813            cx.notify();
20814        }
20815    }
20816
20817    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20818        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20819            && self.focus_handle.is_focused(window)
20820    }
20821
20822    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20823        self.show_cursor_when_unfocused = is_enabled;
20824        cx.notify();
20825    }
20826
20827    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20828        cx.notify();
20829    }
20830
20831    fn on_debug_session_event(
20832        &mut self,
20833        _session: Entity<Session>,
20834        event: &SessionEvent,
20835        cx: &mut Context<Self>,
20836    ) {
20837        if let SessionEvent::InvalidateInlineValue = event {
20838            self.refresh_inline_values(cx);
20839        }
20840    }
20841
20842    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20843        let Some(project) = self.project.clone() else {
20844            return;
20845        };
20846
20847        if !self.inline_value_cache.enabled {
20848            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20849            self.splice_inlays(&inlays, Vec::new(), cx);
20850            return;
20851        }
20852
20853        let current_execution_position = self
20854            .highlighted_rows
20855            .get(&TypeId::of::<ActiveDebugLine>())
20856            .and_then(|lines| lines.last().map(|line| line.range.end));
20857
20858        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20859            let inline_values = editor
20860                .update(cx, |editor, cx| {
20861                    let Some(current_execution_position) = current_execution_position else {
20862                        return Some(Task::ready(Ok(Vec::new())));
20863                    };
20864
20865                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20866                        let snapshot = buffer.snapshot(cx);
20867
20868                        let excerpt = snapshot.excerpt_containing(
20869                            current_execution_position..current_execution_position,
20870                        )?;
20871
20872                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20873                    })?;
20874
20875                    let range =
20876                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20877
20878                    project.inline_values(buffer, range, cx)
20879                })
20880                .ok()
20881                .flatten()?
20882                .await
20883                .context("refreshing debugger inlays")
20884                .log_err()?;
20885
20886            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20887
20888            for (buffer_id, inline_value) in inline_values
20889                .into_iter()
20890                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20891            {
20892                buffer_inline_values
20893                    .entry(buffer_id)
20894                    .or_default()
20895                    .push(inline_value);
20896            }
20897
20898            editor
20899                .update(cx, |editor, cx| {
20900                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20901                    let mut new_inlays = Vec::default();
20902
20903                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20904                        let buffer_id = buffer_snapshot.remote_id();
20905                        buffer_inline_values
20906                            .get(&buffer_id)
20907                            .into_iter()
20908                            .flatten()
20909                            .for_each(|hint| {
20910                                let inlay = Inlay::debugger(
20911                                    post_inc(&mut editor.next_inlay_id),
20912                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20913                                    hint.text(),
20914                                );
20915                                if !inlay.text().chars().contains(&'\n') {
20916                                    new_inlays.push(inlay);
20917                                }
20918                            });
20919                    }
20920
20921                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20922                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20923
20924                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20925                })
20926                .ok()?;
20927            Some(())
20928        });
20929    }
20930
20931    fn on_buffer_event(
20932        &mut self,
20933        multibuffer: &Entity<MultiBuffer>,
20934        event: &multi_buffer::Event,
20935        window: &mut Window,
20936        cx: &mut Context<Self>,
20937    ) {
20938        match event {
20939            multi_buffer::Event::Edited { edited_buffer } => {
20940                self.scrollbar_marker_state.dirty = true;
20941                self.active_indent_guides_state.dirty = true;
20942                self.refresh_active_diagnostics(cx);
20943                self.refresh_code_actions(window, cx);
20944                self.refresh_selected_text_highlights(true, window, cx);
20945                self.refresh_single_line_folds(window, cx);
20946                self.refresh_matching_bracket_highlights(window, cx);
20947                if self.has_active_edit_prediction() {
20948                    self.update_visible_edit_prediction(window, cx);
20949                }
20950
20951                if let Some(buffer) = edited_buffer {
20952                    if buffer.read(cx).file().is_none() {
20953                        cx.emit(EditorEvent::TitleChanged);
20954                    }
20955
20956                    if self.project.is_some() {
20957                        let buffer_id = buffer.read(cx).remote_id();
20958                        self.register_buffer(buffer_id, cx);
20959                        self.update_lsp_data(Some(buffer_id), window, cx);
20960                        self.refresh_inlay_hints(
20961                            InlayHintRefreshReason::BufferEdited(buffer_id),
20962                            cx,
20963                        );
20964                    }
20965                }
20966
20967                cx.emit(EditorEvent::BufferEdited);
20968                cx.emit(SearchEvent::MatchesInvalidated);
20969
20970                let Some(project) = &self.project else { return };
20971                let (telemetry, is_via_ssh) = {
20972                    let project = project.read(cx);
20973                    let telemetry = project.client().telemetry().clone();
20974                    let is_via_ssh = project.is_via_remote_server();
20975                    (telemetry, is_via_ssh)
20976                };
20977                telemetry.log_edit_event("editor", is_via_ssh);
20978            }
20979            multi_buffer::Event::ExcerptsAdded {
20980                buffer,
20981                predecessor,
20982                excerpts,
20983            } => {
20984                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20985                let buffer_id = buffer.read(cx).remote_id();
20986                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20987                    && let Some(project) = &self.project
20988                {
20989                    update_uncommitted_diff_for_buffer(
20990                        cx.entity(),
20991                        project,
20992                        [buffer.clone()],
20993                        self.buffer.clone(),
20994                        cx,
20995                    )
20996                    .detach();
20997                }
20998                self.update_lsp_data(Some(buffer_id), window, cx);
20999                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21000                cx.emit(EditorEvent::ExcerptsAdded {
21001                    buffer: buffer.clone(),
21002                    predecessor: *predecessor,
21003                    excerpts: excerpts.clone(),
21004                });
21005            }
21006            multi_buffer::Event::ExcerptsRemoved {
21007                ids,
21008                removed_buffer_ids,
21009            } => {
21010                if let Some(inlay_hints) = &mut self.inlay_hints {
21011                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21012                }
21013                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21014                for buffer_id in removed_buffer_ids {
21015                    self.registered_buffers.remove(buffer_id);
21016                }
21017                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21018                cx.emit(EditorEvent::ExcerptsRemoved {
21019                    ids: ids.clone(),
21020                    removed_buffer_ids: removed_buffer_ids.clone(),
21021                });
21022            }
21023            multi_buffer::Event::ExcerptsEdited {
21024                excerpt_ids,
21025                buffer_ids,
21026            } => {
21027                self.display_map.update(cx, |map, cx| {
21028                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21029                });
21030                cx.emit(EditorEvent::ExcerptsEdited {
21031                    ids: excerpt_ids.clone(),
21032                });
21033            }
21034            multi_buffer::Event::ExcerptsExpanded { ids } => {
21035                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21036                self.refresh_document_highlights(cx);
21037                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21038            }
21039            multi_buffer::Event::Reparsed(buffer_id) => {
21040                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21041                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21042
21043                cx.emit(EditorEvent::Reparsed(*buffer_id));
21044            }
21045            multi_buffer::Event::DiffHunksToggled => {
21046                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21047            }
21048            multi_buffer::Event::LanguageChanged(buffer_id) => {
21049                self.registered_buffers.remove(&buffer_id);
21050                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21051                cx.emit(EditorEvent::Reparsed(*buffer_id));
21052                cx.notify();
21053            }
21054            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21055            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21056            multi_buffer::Event::FileHandleChanged
21057            | multi_buffer::Event::Reloaded
21058            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21059            multi_buffer::Event::DiagnosticsUpdated => {
21060                self.update_diagnostics_state(window, cx);
21061            }
21062            _ => {}
21063        };
21064    }
21065
21066    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21067        if !self.diagnostics_enabled() {
21068            return;
21069        }
21070        self.refresh_active_diagnostics(cx);
21071        self.refresh_inline_diagnostics(true, window, cx);
21072        self.scrollbar_marker_state.dirty = true;
21073        cx.notify();
21074    }
21075
21076    pub fn start_temporary_diff_override(&mut self) {
21077        self.load_diff_task.take();
21078        self.temporary_diff_override = true;
21079    }
21080
21081    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21082        self.temporary_diff_override = false;
21083        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21084        self.buffer.update(cx, |buffer, cx| {
21085            buffer.set_all_diff_hunks_collapsed(cx);
21086        });
21087
21088        if let Some(project) = self.project.clone() {
21089            self.load_diff_task = Some(
21090                update_uncommitted_diff_for_buffer(
21091                    cx.entity(),
21092                    &project,
21093                    self.buffer.read(cx).all_buffers(),
21094                    self.buffer.clone(),
21095                    cx,
21096                )
21097                .shared(),
21098            );
21099        }
21100    }
21101
21102    fn on_display_map_changed(
21103        &mut self,
21104        _: Entity<DisplayMap>,
21105        _: &mut Window,
21106        cx: &mut Context<Self>,
21107    ) {
21108        cx.notify();
21109    }
21110
21111    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21112        if self.diagnostics_enabled() {
21113            let new_severity = EditorSettings::get_global(cx)
21114                .diagnostics_max_severity
21115                .unwrap_or(DiagnosticSeverity::Hint);
21116            self.set_max_diagnostics_severity(new_severity, cx);
21117        }
21118        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21119        self.update_edit_prediction_settings(cx);
21120        self.refresh_edit_prediction(true, false, window, cx);
21121        self.refresh_inline_values(cx);
21122        self.refresh_inlay_hints(
21123            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21124                self.selections.newest_anchor().head(),
21125                &self.buffer.read(cx).snapshot(cx),
21126                cx,
21127            )),
21128            cx,
21129        );
21130
21131        let old_cursor_shape = self.cursor_shape;
21132        let old_show_breadcrumbs = self.show_breadcrumbs;
21133
21134        {
21135            let editor_settings = EditorSettings::get_global(cx);
21136            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21137            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21138            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21139            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21140        }
21141
21142        if old_cursor_shape != self.cursor_shape {
21143            cx.emit(EditorEvent::CursorShapeChanged);
21144        }
21145
21146        if old_show_breadcrumbs != self.show_breadcrumbs {
21147            cx.emit(EditorEvent::BreadcrumbsChanged);
21148        }
21149
21150        let project_settings = ProjectSettings::get_global(cx);
21151        self.serialize_dirty_buffers =
21152            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21153
21154        if self.mode.is_full() {
21155            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21156            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21157            if self.show_inline_diagnostics != show_inline_diagnostics {
21158                self.show_inline_diagnostics = show_inline_diagnostics;
21159                self.refresh_inline_diagnostics(false, window, cx);
21160            }
21161
21162            if self.git_blame_inline_enabled != inline_blame_enabled {
21163                self.toggle_git_blame_inline_internal(false, window, cx);
21164            }
21165
21166            let minimap_settings = EditorSettings::get_global(cx).minimap;
21167            if self.minimap_visibility != MinimapVisibility::Disabled {
21168                if self.minimap_visibility.settings_visibility()
21169                    != minimap_settings.minimap_enabled()
21170                {
21171                    self.set_minimap_visibility(
21172                        MinimapVisibility::for_mode(self.mode(), cx),
21173                        window,
21174                        cx,
21175                    );
21176                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21177                    minimap_entity.update(cx, |minimap_editor, cx| {
21178                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21179                    })
21180                }
21181            }
21182        }
21183
21184        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21185            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21186        }) {
21187            if !inlay_splice.is_empty() {
21188                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21189            }
21190            self.refresh_colors_for_visible_range(None, window, cx);
21191        }
21192
21193        cx.notify();
21194    }
21195
21196    pub fn set_searchable(&mut self, searchable: bool) {
21197        self.searchable = searchable;
21198    }
21199
21200    pub fn searchable(&self) -> bool {
21201        self.searchable
21202    }
21203
21204    pub fn open_excerpts_in_split(
21205        &mut self,
21206        _: &OpenExcerptsSplit,
21207        window: &mut Window,
21208        cx: &mut Context<Self>,
21209    ) {
21210        self.open_excerpts_common(None, true, window, cx)
21211    }
21212
21213    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21214        self.open_excerpts_common(None, false, window, cx)
21215    }
21216
21217    fn open_excerpts_common(
21218        &mut self,
21219        jump_data: Option<JumpData>,
21220        split: bool,
21221        window: &mut Window,
21222        cx: &mut Context<Self>,
21223    ) {
21224        let Some(workspace) = self.workspace() else {
21225            cx.propagate();
21226            return;
21227        };
21228
21229        if self.buffer.read(cx).is_singleton() {
21230            cx.propagate();
21231            return;
21232        }
21233
21234        let mut new_selections_by_buffer = HashMap::default();
21235        match &jump_data {
21236            Some(JumpData::MultiBufferPoint {
21237                excerpt_id,
21238                position,
21239                anchor,
21240                line_offset_from_top,
21241            }) => {
21242                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21243                if let Some(buffer) = multi_buffer_snapshot
21244                    .buffer_id_for_excerpt(*excerpt_id)
21245                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21246                {
21247                    let buffer_snapshot = buffer.read(cx).snapshot();
21248                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21249                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21250                    } else {
21251                        buffer_snapshot.clip_point(*position, Bias::Left)
21252                    };
21253                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21254                    new_selections_by_buffer.insert(
21255                        buffer,
21256                        (
21257                            vec![jump_to_offset..jump_to_offset],
21258                            Some(*line_offset_from_top),
21259                        ),
21260                    );
21261                }
21262            }
21263            Some(JumpData::MultiBufferRow {
21264                row,
21265                line_offset_from_top,
21266            }) => {
21267                let point = MultiBufferPoint::new(row.0, 0);
21268                if let Some((buffer, buffer_point, _)) =
21269                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21270                {
21271                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21272                    new_selections_by_buffer
21273                        .entry(buffer)
21274                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21275                        .0
21276                        .push(buffer_offset..buffer_offset)
21277                }
21278            }
21279            None => {
21280                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21281                let multi_buffer = self.buffer.read(cx);
21282                for selection in selections {
21283                    for (snapshot, range, _, anchor) in multi_buffer
21284                        .snapshot(cx)
21285                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21286                    {
21287                        if let Some(anchor) = anchor {
21288                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21289                            else {
21290                                continue;
21291                            };
21292                            let offset = text::ToOffset::to_offset(
21293                                &anchor.text_anchor,
21294                                &buffer_handle.read(cx).snapshot(),
21295                            );
21296                            let range = offset..offset;
21297                            new_selections_by_buffer
21298                                .entry(buffer_handle)
21299                                .or_insert((Vec::new(), None))
21300                                .0
21301                                .push(range)
21302                        } else {
21303                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21304                            else {
21305                                continue;
21306                            };
21307                            new_selections_by_buffer
21308                                .entry(buffer_handle)
21309                                .or_insert((Vec::new(), None))
21310                                .0
21311                                .push(range)
21312                        }
21313                    }
21314                }
21315            }
21316        }
21317
21318        new_selections_by_buffer
21319            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21320
21321        if new_selections_by_buffer.is_empty() {
21322            return;
21323        }
21324
21325        // We defer the pane interaction because we ourselves are a workspace item
21326        // and activating a new item causes the pane to call a method on us reentrantly,
21327        // which panics if we're on the stack.
21328        window.defer(cx, move |window, cx| {
21329            workspace.update(cx, |workspace, cx| {
21330                let pane = if split {
21331                    workspace.adjacent_pane(window, cx)
21332                } else {
21333                    workspace.active_pane().clone()
21334                };
21335
21336                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21337                    let editor = buffer
21338                        .read(cx)
21339                        .file()
21340                        .is_none()
21341                        .then(|| {
21342                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21343                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21344                            // Instead, we try to activate the existing editor in the pane first.
21345                            let (editor, pane_item_index) =
21346                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21347                                    let editor = item.downcast::<Editor>()?;
21348                                    let singleton_buffer =
21349                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21350                                    if singleton_buffer == buffer {
21351                                        Some((editor, i))
21352                                    } else {
21353                                        None
21354                                    }
21355                                })?;
21356                            pane.update(cx, |pane, cx| {
21357                                pane.activate_item(pane_item_index, true, true, window, cx)
21358                            });
21359                            Some(editor)
21360                        })
21361                        .flatten()
21362                        .unwrap_or_else(|| {
21363                            workspace.open_project_item::<Self>(
21364                                pane.clone(),
21365                                buffer,
21366                                true,
21367                                true,
21368                                window,
21369                                cx,
21370                            )
21371                        });
21372
21373                    editor.update(cx, |editor, cx| {
21374                        let autoscroll = match scroll_offset {
21375                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21376                            None => Autoscroll::newest(),
21377                        };
21378                        let nav_history = editor.nav_history.take();
21379                        editor.change_selections(
21380                            SelectionEffects::scroll(autoscroll),
21381                            window,
21382                            cx,
21383                            |s| {
21384                                s.select_ranges(ranges);
21385                            },
21386                        );
21387                        editor.nav_history = nav_history;
21388                    });
21389                }
21390            })
21391        });
21392    }
21393
21394    // For now, don't allow opening excerpts in buffers that aren't backed by
21395    // regular project files.
21396    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21397        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21398    }
21399
21400    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21401        let snapshot = self.buffer.read(cx).read(cx);
21402        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21403        Some(
21404            ranges
21405                .iter()
21406                .map(move |range| {
21407                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21408                })
21409                .collect(),
21410        )
21411    }
21412
21413    fn selection_replacement_ranges(
21414        &self,
21415        range: Range<OffsetUtf16>,
21416        cx: &mut App,
21417    ) -> Vec<Range<OffsetUtf16>> {
21418        let selections = self
21419            .selections
21420            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21421        let newest_selection = selections
21422            .iter()
21423            .max_by_key(|selection| selection.id)
21424            .unwrap();
21425        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21426        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21427        let snapshot = self.buffer.read(cx).read(cx);
21428        selections
21429            .into_iter()
21430            .map(|mut selection| {
21431                selection.start.0 =
21432                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21433                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21434                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21435                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21436            })
21437            .collect()
21438    }
21439
21440    fn report_editor_event(
21441        &self,
21442        reported_event: ReportEditorEvent,
21443        file_extension: Option<String>,
21444        cx: &App,
21445    ) {
21446        if cfg!(any(test, feature = "test-support")) {
21447            return;
21448        }
21449
21450        let Some(project) = &self.project else { return };
21451
21452        // If None, we are in a file without an extension
21453        let file = self
21454            .buffer
21455            .read(cx)
21456            .as_singleton()
21457            .and_then(|b| b.read(cx).file());
21458        let file_extension = file_extension.or(file
21459            .as_ref()
21460            .and_then(|file| Path::new(file.file_name(cx)).extension())
21461            .and_then(|e| e.to_str())
21462            .map(|a| a.to_string()));
21463
21464        let vim_mode = vim_flavor(cx).is_some();
21465
21466        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21467        let copilot_enabled = edit_predictions_provider
21468            == language::language_settings::EditPredictionProvider::Copilot;
21469        let copilot_enabled_for_language = self
21470            .buffer
21471            .read(cx)
21472            .language_settings(cx)
21473            .show_edit_predictions;
21474
21475        let project = project.read(cx);
21476        let event_type = reported_event.event_type();
21477
21478        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21479            telemetry::event!(
21480                event_type,
21481                type = if auto_saved {"autosave"} else {"manual"},
21482                file_extension,
21483                vim_mode,
21484                copilot_enabled,
21485                copilot_enabled_for_language,
21486                edit_predictions_provider,
21487                is_via_ssh = project.is_via_remote_server(),
21488            );
21489        } else {
21490            telemetry::event!(
21491                event_type,
21492                file_extension,
21493                vim_mode,
21494                copilot_enabled,
21495                copilot_enabled_for_language,
21496                edit_predictions_provider,
21497                is_via_ssh = project.is_via_remote_server(),
21498            );
21499        };
21500    }
21501
21502    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21503    /// with each line being an array of {text, highlight} objects.
21504    fn copy_highlight_json(
21505        &mut self,
21506        _: &CopyHighlightJson,
21507        window: &mut Window,
21508        cx: &mut Context<Self>,
21509    ) {
21510        #[derive(Serialize)]
21511        struct Chunk<'a> {
21512            text: String,
21513            highlight: Option<&'a str>,
21514        }
21515
21516        let snapshot = self.buffer.read(cx).snapshot(cx);
21517        let range = self
21518            .selected_text_range(false, window, cx)
21519            .and_then(|selection| {
21520                if selection.range.is_empty() {
21521                    None
21522                } else {
21523                    Some(
21524                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21525                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21526                    )
21527                }
21528            })
21529            .unwrap_or_else(|| 0..snapshot.len());
21530
21531        let chunks = snapshot.chunks(range, true);
21532        let mut lines = Vec::new();
21533        let mut line: VecDeque<Chunk> = VecDeque::new();
21534
21535        let Some(style) = self.style.as_ref() else {
21536            return;
21537        };
21538
21539        for chunk in chunks {
21540            let highlight = chunk
21541                .syntax_highlight_id
21542                .and_then(|id| id.name(&style.syntax));
21543            let mut chunk_lines = chunk.text.split('\n').peekable();
21544            while let Some(text) = chunk_lines.next() {
21545                let mut merged_with_last_token = false;
21546                if let Some(last_token) = line.back_mut()
21547                    && last_token.highlight == highlight
21548                {
21549                    last_token.text.push_str(text);
21550                    merged_with_last_token = true;
21551                }
21552
21553                if !merged_with_last_token {
21554                    line.push_back(Chunk {
21555                        text: text.into(),
21556                        highlight,
21557                    });
21558                }
21559
21560                if chunk_lines.peek().is_some() {
21561                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21562                        line.pop_front();
21563                    }
21564                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21565                        line.pop_back();
21566                    }
21567
21568                    lines.push(mem::take(&mut line));
21569                }
21570            }
21571        }
21572
21573        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21574            return;
21575        };
21576        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21577    }
21578
21579    pub fn open_context_menu(
21580        &mut self,
21581        _: &OpenContextMenu,
21582        window: &mut Window,
21583        cx: &mut Context<Self>,
21584    ) {
21585        self.request_autoscroll(Autoscroll::newest(), cx);
21586        let position = self
21587            .selections
21588            .newest_display(&self.display_snapshot(cx))
21589            .start;
21590        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21591    }
21592
21593    pub fn replay_insert_event(
21594        &mut self,
21595        text: &str,
21596        relative_utf16_range: Option<Range<isize>>,
21597        window: &mut Window,
21598        cx: &mut Context<Self>,
21599    ) {
21600        if !self.input_enabled {
21601            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21602            return;
21603        }
21604        if let Some(relative_utf16_range) = relative_utf16_range {
21605            let selections = self
21606                .selections
21607                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21608            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21609                let new_ranges = selections.into_iter().map(|range| {
21610                    let start = OffsetUtf16(
21611                        range
21612                            .head()
21613                            .0
21614                            .saturating_add_signed(relative_utf16_range.start),
21615                    );
21616                    let end = OffsetUtf16(
21617                        range
21618                            .head()
21619                            .0
21620                            .saturating_add_signed(relative_utf16_range.end),
21621                    );
21622                    start..end
21623                });
21624                s.select_ranges(new_ranges);
21625            });
21626        }
21627
21628        self.handle_input(text, window, cx);
21629    }
21630
21631    pub fn is_focused(&self, window: &Window) -> bool {
21632        self.focus_handle.is_focused(window)
21633    }
21634
21635    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21636        cx.emit(EditorEvent::Focused);
21637
21638        if let Some(descendant) = self
21639            .last_focused_descendant
21640            .take()
21641            .and_then(|descendant| descendant.upgrade())
21642        {
21643            window.focus(&descendant);
21644        } else {
21645            if let Some(blame) = self.blame.as_ref() {
21646                blame.update(cx, GitBlame::focus)
21647            }
21648
21649            self.blink_manager.update(cx, BlinkManager::enable);
21650            self.show_cursor_names(window, cx);
21651            self.buffer.update(cx, |buffer, cx| {
21652                buffer.finalize_last_transaction(cx);
21653                if self.leader_id.is_none() {
21654                    buffer.set_active_selections(
21655                        &self.selections.disjoint_anchors_arc(),
21656                        self.selections.line_mode(),
21657                        self.cursor_shape,
21658                        cx,
21659                    );
21660                }
21661            });
21662        }
21663    }
21664
21665    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21666        cx.emit(EditorEvent::FocusedIn)
21667    }
21668
21669    fn handle_focus_out(
21670        &mut self,
21671        event: FocusOutEvent,
21672        _window: &mut Window,
21673        cx: &mut Context<Self>,
21674    ) {
21675        if event.blurred != self.focus_handle {
21676            self.last_focused_descendant = Some(event.blurred);
21677        }
21678        self.selection_drag_state = SelectionDragState::None;
21679        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21680    }
21681
21682    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21683        self.blink_manager.update(cx, BlinkManager::disable);
21684        self.buffer
21685            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21686
21687        if let Some(blame) = self.blame.as_ref() {
21688            blame.update(cx, GitBlame::blur)
21689        }
21690        if !self.hover_state.focused(window, cx) {
21691            hide_hover(self, cx);
21692        }
21693        if !self
21694            .context_menu
21695            .borrow()
21696            .as_ref()
21697            .is_some_and(|context_menu| context_menu.focused(window, cx))
21698        {
21699            self.hide_context_menu(window, cx);
21700        }
21701        self.take_active_edit_prediction(cx);
21702        cx.emit(EditorEvent::Blurred);
21703        cx.notify();
21704    }
21705
21706    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21707        let mut pending: String = window
21708            .pending_input_keystrokes()
21709            .into_iter()
21710            .flatten()
21711            .filter_map(|keystroke| {
21712                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21713                    keystroke.key_char.clone()
21714                } else {
21715                    None
21716                }
21717            })
21718            .collect();
21719
21720        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21721            pending = "".to_string();
21722        }
21723
21724        let existing_pending = self
21725            .text_highlights::<PendingInput>(cx)
21726            .map(|(_, ranges)| ranges.to_vec());
21727        if existing_pending.is_none() && pending.is_empty() {
21728            return;
21729        }
21730        let transaction =
21731            self.transact(window, cx, |this, window, cx| {
21732                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21733                let edits = selections
21734                    .iter()
21735                    .map(|selection| (selection.end..selection.end, pending.clone()));
21736                this.edit(edits, cx);
21737                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21738                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21739                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21740                    }));
21741                });
21742                if let Some(existing_ranges) = existing_pending {
21743                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21744                    this.edit(edits, cx);
21745                }
21746            });
21747
21748        let snapshot = self.snapshot(window, cx);
21749        let ranges = self
21750            .selections
21751            .all::<usize>(&snapshot.display_snapshot)
21752            .into_iter()
21753            .map(|selection| {
21754                snapshot.buffer_snapshot().anchor_after(selection.end)
21755                    ..snapshot
21756                        .buffer_snapshot()
21757                        .anchor_before(selection.end + pending.len())
21758            })
21759            .collect();
21760
21761        if pending.is_empty() {
21762            self.clear_highlights::<PendingInput>(cx);
21763        } else {
21764            self.highlight_text::<PendingInput>(
21765                ranges,
21766                HighlightStyle {
21767                    underline: Some(UnderlineStyle {
21768                        thickness: px(1.),
21769                        color: None,
21770                        wavy: false,
21771                    }),
21772                    ..Default::default()
21773                },
21774                cx,
21775            );
21776        }
21777
21778        self.ime_transaction = self.ime_transaction.or(transaction);
21779        if let Some(transaction) = self.ime_transaction {
21780            self.buffer.update(cx, |buffer, cx| {
21781                buffer.group_until_transaction(transaction, cx);
21782            });
21783        }
21784
21785        if self.text_highlights::<PendingInput>(cx).is_none() {
21786            self.ime_transaction.take();
21787        }
21788    }
21789
21790    pub fn register_action_renderer(
21791        &mut self,
21792        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21793    ) -> Subscription {
21794        let id = self.next_editor_action_id.post_inc();
21795        self.editor_actions
21796            .borrow_mut()
21797            .insert(id, Box::new(listener));
21798
21799        let editor_actions = self.editor_actions.clone();
21800        Subscription::new(move || {
21801            editor_actions.borrow_mut().remove(&id);
21802        })
21803    }
21804
21805    pub fn register_action<A: Action>(
21806        &mut self,
21807        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21808    ) -> Subscription {
21809        let id = self.next_editor_action_id.post_inc();
21810        let listener = Arc::new(listener);
21811        self.editor_actions.borrow_mut().insert(
21812            id,
21813            Box::new(move |_, window, _| {
21814                let listener = listener.clone();
21815                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21816                    let action = action.downcast_ref().unwrap();
21817                    if phase == DispatchPhase::Bubble {
21818                        listener(action, window, cx)
21819                    }
21820                })
21821            }),
21822        );
21823
21824        let editor_actions = self.editor_actions.clone();
21825        Subscription::new(move || {
21826            editor_actions.borrow_mut().remove(&id);
21827        })
21828    }
21829
21830    pub fn file_header_size(&self) -> u32 {
21831        FILE_HEADER_HEIGHT
21832    }
21833
21834    pub fn restore(
21835        &mut self,
21836        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21837        window: &mut Window,
21838        cx: &mut Context<Self>,
21839    ) {
21840        let workspace = self.workspace();
21841        let project = self.project();
21842        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21843            let mut tasks = Vec::new();
21844            for (buffer_id, changes) in revert_changes {
21845                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21846                    buffer.update(cx, |buffer, cx| {
21847                        buffer.edit(
21848                            changes
21849                                .into_iter()
21850                                .map(|(range, text)| (range, text.to_string())),
21851                            None,
21852                            cx,
21853                        );
21854                    });
21855
21856                    if let Some(project) =
21857                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21858                    {
21859                        project.update(cx, |project, cx| {
21860                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21861                        })
21862                    }
21863                }
21864            }
21865            tasks
21866        });
21867        cx.spawn_in(window, async move |_, cx| {
21868            for (buffer, task) in save_tasks {
21869                let result = task.await;
21870                if result.is_err() {
21871                    let Some(path) = buffer
21872                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21873                        .ok()
21874                    else {
21875                        continue;
21876                    };
21877                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21878                        let Some(task) = cx
21879                            .update_window_entity(workspace, |workspace, window, cx| {
21880                                workspace
21881                                    .open_path_preview(path, None, false, false, false, window, cx)
21882                            })
21883                            .ok()
21884                        else {
21885                            continue;
21886                        };
21887                        task.await.log_err();
21888                    }
21889                }
21890            }
21891        })
21892        .detach();
21893        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21894            selections.refresh()
21895        });
21896    }
21897
21898    pub fn to_pixel_point(
21899        &self,
21900        source: multi_buffer::Anchor,
21901        editor_snapshot: &EditorSnapshot,
21902        window: &mut Window,
21903    ) -> Option<gpui::Point<Pixels>> {
21904        let source_point = source.to_display_point(editor_snapshot);
21905        self.display_to_pixel_point(source_point, editor_snapshot, window)
21906    }
21907
21908    pub fn display_to_pixel_point(
21909        &self,
21910        source: DisplayPoint,
21911        editor_snapshot: &EditorSnapshot,
21912        window: &mut Window,
21913    ) -> Option<gpui::Point<Pixels>> {
21914        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21915        let text_layout_details = self.text_layout_details(window);
21916        let scroll_top = text_layout_details
21917            .scroll_anchor
21918            .scroll_position(editor_snapshot)
21919            .y;
21920
21921        if source.row().as_f64() < scroll_top.floor() {
21922            return None;
21923        }
21924        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21925        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21926        Some(gpui::Point::new(source_x, source_y))
21927    }
21928
21929    pub fn has_visible_completions_menu(&self) -> bool {
21930        !self.edit_prediction_preview_is_active()
21931            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21932                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21933            })
21934    }
21935
21936    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21937        if self.mode.is_minimap() {
21938            return;
21939        }
21940        self.addons
21941            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21942    }
21943
21944    pub fn unregister_addon<T: Addon>(&mut self) {
21945        self.addons.remove(&std::any::TypeId::of::<T>());
21946    }
21947
21948    pub fn addon<T: Addon>(&self) -> Option<&T> {
21949        let type_id = std::any::TypeId::of::<T>();
21950        self.addons
21951            .get(&type_id)
21952            .and_then(|item| item.to_any().downcast_ref::<T>())
21953    }
21954
21955    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21956        let type_id = std::any::TypeId::of::<T>();
21957        self.addons
21958            .get_mut(&type_id)
21959            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21960    }
21961
21962    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21963        let text_layout_details = self.text_layout_details(window);
21964        let style = &text_layout_details.editor_style;
21965        let font_id = window.text_system().resolve_font(&style.text.font());
21966        let font_size = style.text.font_size.to_pixels(window.rem_size());
21967        let line_height = style.text.line_height_in_pixels(window.rem_size());
21968        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21969        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21970
21971        CharacterDimensions {
21972            em_width,
21973            em_advance,
21974            line_height,
21975        }
21976    }
21977
21978    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21979        self.load_diff_task.clone()
21980    }
21981
21982    fn read_metadata_from_db(
21983        &mut self,
21984        item_id: u64,
21985        workspace_id: WorkspaceId,
21986        window: &mut Window,
21987        cx: &mut Context<Editor>,
21988    ) {
21989        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21990            && !self.mode.is_minimap()
21991            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21992        {
21993            let buffer_snapshot = OnceCell::new();
21994
21995            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21996                && !folds.is_empty()
21997            {
21998                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21999                self.fold_ranges(
22000                    folds
22001                        .into_iter()
22002                        .map(|(start, end)| {
22003                            snapshot.clip_offset(start, Bias::Left)
22004                                ..snapshot.clip_offset(end, Bias::Right)
22005                        })
22006                        .collect(),
22007                    false,
22008                    window,
22009                    cx,
22010                );
22011            }
22012
22013            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22014                && !selections.is_empty()
22015            {
22016                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22017                // skip adding the initial selection to selection history
22018                self.selection_history.mode = SelectionHistoryMode::Skipping;
22019                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22020                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22021                        snapshot.clip_offset(start, Bias::Left)
22022                            ..snapshot.clip_offset(end, Bias::Right)
22023                    }));
22024                });
22025                self.selection_history.mode = SelectionHistoryMode::Normal;
22026            };
22027        }
22028
22029        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22030    }
22031
22032    fn update_lsp_data(
22033        &mut self,
22034        for_buffer: Option<BufferId>,
22035        window: &mut Window,
22036        cx: &mut Context<'_, Self>,
22037    ) {
22038        self.pull_diagnostics(for_buffer, window, cx);
22039        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22040    }
22041
22042    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22043        if self.ignore_lsp_data() {
22044            return;
22045        }
22046        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22047            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22048        }
22049    }
22050
22051    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22052        if !self.registered_buffers.contains_key(&buffer_id)
22053            && let Some(project) = self.project.as_ref()
22054        {
22055            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22056                project.update(cx, |project, cx| {
22057                    self.registered_buffers.insert(
22058                        buffer_id,
22059                        project.register_buffer_with_language_servers(&buffer, cx),
22060                    );
22061                });
22062            } else {
22063                self.registered_buffers.remove(&buffer_id);
22064            }
22065        }
22066    }
22067
22068    fn ignore_lsp_data(&self) -> bool {
22069        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22070        // skip any LSP updates for it.
22071        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22072    }
22073}
22074
22075fn edit_for_markdown_paste<'a>(
22076    buffer: &MultiBufferSnapshot,
22077    range: Range<usize>,
22078    to_insert: &'a str,
22079    url: Option<url::Url>,
22080) -> (Range<usize>, Cow<'a, str>) {
22081    if url.is_none() {
22082        return (range, Cow::Borrowed(to_insert));
22083    };
22084
22085    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22086
22087    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22088        Cow::Borrowed(to_insert)
22089    } else {
22090        Cow::Owned(format!("[{old_text}]({to_insert})"))
22091    };
22092    (range, new_text)
22093}
22094
22095#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22096pub enum VimFlavor {
22097    Vim,
22098    Helix,
22099}
22100
22101pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22102    if vim_mode_setting::HelixModeSetting::try_get(cx)
22103        .map(|helix_mode| helix_mode.0)
22104        .unwrap_or(false)
22105    {
22106        Some(VimFlavor::Helix)
22107    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22108        .map(|vim_mode| vim_mode.0)
22109        .unwrap_or(false)
22110    {
22111        Some(VimFlavor::Vim)
22112    } else {
22113        None // neither vim nor helix mode
22114    }
22115}
22116
22117fn process_completion_for_edit(
22118    completion: &Completion,
22119    intent: CompletionIntent,
22120    buffer: &Entity<Buffer>,
22121    cursor_position: &text::Anchor,
22122    cx: &mut Context<Editor>,
22123) -> CompletionEdit {
22124    let buffer = buffer.read(cx);
22125    let buffer_snapshot = buffer.snapshot();
22126    let (snippet, new_text) = if completion.is_snippet() {
22127        let mut snippet_source = completion.new_text.clone();
22128        // Workaround for typescript language server issues so that methods don't expand within
22129        // strings and functions with type expressions. The previous point is used because the query
22130        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22131        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22132        let previous_point = if previous_point.column > 0 {
22133            cursor_position.to_previous_offset(&buffer_snapshot)
22134        } else {
22135            cursor_position.to_offset(&buffer_snapshot)
22136        };
22137        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22138            && scope.prefers_label_for_snippet_in_completion()
22139            && let Some(label) = completion.label()
22140            && matches!(
22141                completion.kind(),
22142                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22143            )
22144        {
22145            snippet_source = label;
22146        }
22147        match Snippet::parse(&snippet_source).log_err() {
22148            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22149            None => (None, completion.new_text.clone()),
22150        }
22151    } else {
22152        (None, completion.new_text.clone())
22153    };
22154
22155    let mut range_to_replace = {
22156        let replace_range = &completion.replace_range;
22157        if let CompletionSource::Lsp {
22158            insert_range: Some(insert_range),
22159            ..
22160        } = &completion.source
22161        {
22162            debug_assert_eq!(
22163                insert_range.start, replace_range.start,
22164                "insert_range and replace_range should start at the same position"
22165            );
22166            debug_assert!(
22167                insert_range
22168                    .start
22169                    .cmp(cursor_position, &buffer_snapshot)
22170                    .is_le(),
22171                "insert_range should start before or at cursor position"
22172            );
22173            debug_assert!(
22174                replace_range
22175                    .start
22176                    .cmp(cursor_position, &buffer_snapshot)
22177                    .is_le(),
22178                "replace_range should start before or at cursor position"
22179            );
22180
22181            let should_replace = match intent {
22182                CompletionIntent::CompleteWithInsert => false,
22183                CompletionIntent::CompleteWithReplace => true,
22184                CompletionIntent::Complete | CompletionIntent::Compose => {
22185                    let insert_mode =
22186                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22187                            .completions
22188                            .lsp_insert_mode;
22189                    match insert_mode {
22190                        LspInsertMode::Insert => false,
22191                        LspInsertMode::Replace => true,
22192                        LspInsertMode::ReplaceSubsequence => {
22193                            let mut text_to_replace = buffer.chars_for_range(
22194                                buffer.anchor_before(replace_range.start)
22195                                    ..buffer.anchor_after(replace_range.end),
22196                            );
22197                            let mut current_needle = text_to_replace.next();
22198                            for haystack_ch in completion.label.text.chars() {
22199                                if let Some(needle_ch) = current_needle
22200                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22201                                {
22202                                    current_needle = text_to_replace.next();
22203                                }
22204                            }
22205                            current_needle.is_none()
22206                        }
22207                        LspInsertMode::ReplaceSuffix => {
22208                            if replace_range
22209                                .end
22210                                .cmp(cursor_position, &buffer_snapshot)
22211                                .is_gt()
22212                            {
22213                                let range_after_cursor = *cursor_position..replace_range.end;
22214                                let text_after_cursor = buffer
22215                                    .text_for_range(
22216                                        buffer.anchor_before(range_after_cursor.start)
22217                                            ..buffer.anchor_after(range_after_cursor.end),
22218                                    )
22219                                    .collect::<String>()
22220                                    .to_ascii_lowercase();
22221                                completion
22222                                    .label
22223                                    .text
22224                                    .to_ascii_lowercase()
22225                                    .ends_with(&text_after_cursor)
22226                            } else {
22227                                true
22228                            }
22229                        }
22230                    }
22231                }
22232            };
22233
22234            if should_replace {
22235                replace_range.clone()
22236            } else {
22237                insert_range.clone()
22238            }
22239        } else {
22240            replace_range.clone()
22241        }
22242    };
22243
22244    if range_to_replace
22245        .end
22246        .cmp(cursor_position, &buffer_snapshot)
22247        .is_lt()
22248    {
22249        range_to_replace.end = *cursor_position;
22250    }
22251
22252    CompletionEdit {
22253        new_text,
22254        replace_range: range_to_replace.to_offset(buffer),
22255        snippet,
22256    }
22257}
22258
22259struct CompletionEdit {
22260    new_text: String,
22261    replace_range: Range<usize>,
22262    snippet: Option<Snippet>,
22263}
22264
22265fn insert_extra_newline_brackets(
22266    buffer: &MultiBufferSnapshot,
22267    range: Range<usize>,
22268    language: &language::LanguageScope,
22269) -> bool {
22270    let leading_whitespace_len = buffer
22271        .reversed_chars_at(range.start)
22272        .take_while(|c| c.is_whitespace() && *c != '\n')
22273        .map(|c| c.len_utf8())
22274        .sum::<usize>();
22275    let trailing_whitespace_len = buffer
22276        .chars_at(range.end)
22277        .take_while(|c| c.is_whitespace() && *c != '\n')
22278        .map(|c| c.len_utf8())
22279        .sum::<usize>();
22280    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22281
22282    language.brackets().any(|(pair, enabled)| {
22283        let pair_start = pair.start.trim_end();
22284        let pair_end = pair.end.trim_start();
22285
22286        enabled
22287            && pair.newline
22288            && buffer.contains_str_at(range.end, pair_end)
22289            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22290    })
22291}
22292
22293fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22294    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22295        [(buffer, range, _)] => (*buffer, range.clone()),
22296        _ => return false,
22297    };
22298    let pair = {
22299        let mut result: Option<BracketMatch> = None;
22300
22301        for pair in buffer
22302            .all_bracket_ranges(range.clone())
22303            .filter(move |pair| {
22304                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22305            })
22306        {
22307            let len = pair.close_range.end - pair.open_range.start;
22308
22309            if let Some(existing) = &result {
22310                let existing_len = existing.close_range.end - existing.open_range.start;
22311                if len > existing_len {
22312                    continue;
22313                }
22314            }
22315
22316            result = Some(pair);
22317        }
22318
22319        result
22320    };
22321    let Some(pair) = pair else {
22322        return false;
22323    };
22324    pair.newline_only
22325        && buffer
22326            .chars_for_range(pair.open_range.end..range.start)
22327            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22328            .all(|c| c.is_whitespace() && c != '\n')
22329}
22330
22331fn update_uncommitted_diff_for_buffer(
22332    editor: Entity<Editor>,
22333    project: &Entity<Project>,
22334    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22335    buffer: Entity<MultiBuffer>,
22336    cx: &mut App,
22337) -> Task<()> {
22338    let mut tasks = Vec::new();
22339    project.update(cx, |project, cx| {
22340        for buffer in buffers {
22341            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22342                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22343            }
22344        }
22345    });
22346    cx.spawn(async move |cx| {
22347        let diffs = future::join_all(tasks).await;
22348        if editor
22349            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22350            .unwrap_or(false)
22351        {
22352            return;
22353        }
22354
22355        buffer
22356            .update(cx, |buffer, cx| {
22357                for diff in diffs.into_iter().flatten() {
22358                    buffer.add_diff(diff, cx);
22359                }
22360            })
22361            .ok();
22362    })
22363}
22364
22365fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22366    let tab_size = tab_size.get() as usize;
22367    let mut width = offset;
22368
22369    for ch in text.chars() {
22370        width += if ch == '\t' {
22371            tab_size - (width % tab_size)
22372        } else {
22373            1
22374        };
22375    }
22376
22377    width - offset
22378}
22379
22380#[cfg(test)]
22381mod tests {
22382    use super::*;
22383
22384    #[test]
22385    fn test_string_size_with_expanded_tabs() {
22386        let nz = |val| NonZeroU32::new(val).unwrap();
22387        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22388        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22389        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22390        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22391        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22392        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22393        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22394        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22395    }
22396}
22397
22398/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22399struct WordBreakingTokenizer<'a> {
22400    input: &'a str,
22401}
22402
22403impl<'a> WordBreakingTokenizer<'a> {
22404    fn new(input: &'a str) -> Self {
22405        Self { input }
22406    }
22407}
22408
22409fn is_char_ideographic(ch: char) -> bool {
22410    use unicode_script::Script::*;
22411    use unicode_script::UnicodeScript;
22412    matches!(ch.script(), Han | Tangut | Yi)
22413}
22414
22415fn is_grapheme_ideographic(text: &str) -> bool {
22416    text.chars().any(is_char_ideographic)
22417}
22418
22419fn is_grapheme_whitespace(text: &str) -> bool {
22420    text.chars().any(|x| x.is_whitespace())
22421}
22422
22423fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22424    text.chars()
22425        .next()
22426        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22427}
22428
22429#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22430enum WordBreakToken<'a> {
22431    Word { token: &'a str, grapheme_len: usize },
22432    InlineWhitespace { token: &'a str, grapheme_len: usize },
22433    Newline,
22434}
22435
22436impl<'a> Iterator for WordBreakingTokenizer<'a> {
22437    /// Yields a span, the count of graphemes in the token, and whether it was
22438    /// whitespace. Note that it also breaks at word boundaries.
22439    type Item = WordBreakToken<'a>;
22440
22441    fn next(&mut self) -> Option<Self::Item> {
22442        use unicode_segmentation::UnicodeSegmentation;
22443        if self.input.is_empty() {
22444            return None;
22445        }
22446
22447        let mut iter = self.input.graphemes(true).peekable();
22448        let mut offset = 0;
22449        let mut grapheme_len = 0;
22450        if let Some(first_grapheme) = iter.next() {
22451            let is_newline = first_grapheme == "\n";
22452            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22453            offset += first_grapheme.len();
22454            grapheme_len += 1;
22455            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22456                if let Some(grapheme) = iter.peek().copied()
22457                    && should_stay_with_preceding_ideograph(grapheme)
22458                {
22459                    offset += grapheme.len();
22460                    grapheme_len += 1;
22461                }
22462            } else {
22463                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22464                let mut next_word_bound = words.peek().copied();
22465                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22466                    next_word_bound = words.next();
22467                }
22468                while let Some(grapheme) = iter.peek().copied() {
22469                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22470                        break;
22471                    };
22472                    if is_grapheme_whitespace(grapheme) != is_whitespace
22473                        || (grapheme == "\n") != is_newline
22474                    {
22475                        break;
22476                    };
22477                    offset += grapheme.len();
22478                    grapheme_len += 1;
22479                    iter.next();
22480                }
22481            }
22482            let token = &self.input[..offset];
22483            self.input = &self.input[offset..];
22484            if token == "\n" {
22485                Some(WordBreakToken::Newline)
22486            } else if is_whitespace {
22487                Some(WordBreakToken::InlineWhitespace {
22488                    token,
22489                    grapheme_len,
22490                })
22491            } else {
22492                Some(WordBreakToken::Word {
22493                    token,
22494                    grapheme_len,
22495                })
22496            }
22497        } else {
22498            None
22499        }
22500    }
22501}
22502
22503#[test]
22504fn test_word_breaking_tokenizer() {
22505    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22506        ("", &[]),
22507        ("  ", &[whitespace("  ", 2)]),
22508        ("Ʒ", &[word("Ʒ", 1)]),
22509        ("Ǽ", &[word("Ǽ", 1)]),
22510        ("", &[word("", 1)]),
22511        ("⋑⋑", &[word("⋑⋑", 2)]),
22512        (
22513            "原理,进而",
22514            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22515        ),
22516        (
22517            "hello world",
22518            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22519        ),
22520        (
22521            "hello, world",
22522            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22523        ),
22524        (
22525            "  hello world",
22526            &[
22527                whitespace("  ", 2),
22528                word("hello", 5),
22529                whitespace(" ", 1),
22530                word("world", 5),
22531            ],
22532        ),
22533        (
22534            "这是什么 \n 钢笔",
22535            &[
22536                word("", 1),
22537                word("", 1),
22538                word("", 1),
22539                word("", 1),
22540                whitespace(" ", 1),
22541                newline(),
22542                whitespace(" ", 1),
22543                word("", 1),
22544                word("", 1),
22545            ],
22546        ),
22547        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22548    ];
22549
22550    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22551        WordBreakToken::Word {
22552            token,
22553            grapheme_len,
22554        }
22555    }
22556
22557    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22558        WordBreakToken::InlineWhitespace {
22559            token,
22560            grapheme_len,
22561        }
22562    }
22563
22564    fn newline() -> WordBreakToken<'static> {
22565        WordBreakToken::Newline
22566    }
22567
22568    for (input, result) in tests {
22569        assert_eq!(
22570            WordBreakingTokenizer::new(input)
22571                .collect::<Vec<_>>()
22572                .as_slice(),
22573            *result,
22574        );
22575    }
22576}
22577
22578fn wrap_with_prefix(
22579    first_line_prefix: String,
22580    subsequent_lines_prefix: String,
22581    unwrapped_text: String,
22582    wrap_column: usize,
22583    tab_size: NonZeroU32,
22584    preserve_existing_whitespace: bool,
22585) -> String {
22586    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22587    let subsequent_lines_prefix_len =
22588        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22589    let mut wrapped_text = String::new();
22590    let mut current_line = first_line_prefix;
22591    let mut is_first_line = true;
22592
22593    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22594    let mut current_line_len = first_line_prefix_len;
22595    let mut in_whitespace = false;
22596    for token in tokenizer {
22597        let have_preceding_whitespace = in_whitespace;
22598        match token {
22599            WordBreakToken::Word {
22600                token,
22601                grapheme_len,
22602            } => {
22603                in_whitespace = false;
22604                let current_prefix_len = if is_first_line {
22605                    first_line_prefix_len
22606                } else {
22607                    subsequent_lines_prefix_len
22608                };
22609                if current_line_len + grapheme_len > wrap_column
22610                    && current_line_len != current_prefix_len
22611                {
22612                    wrapped_text.push_str(current_line.trim_end());
22613                    wrapped_text.push('\n');
22614                    is_first_line = false;
22615                    current_line = subsequent_lines_prefix.clone();
22616                    current_line_len = subsequent_lines_prefix_len;
22617                }
22618                current_line.push_str(token);
22619                current_line_len += grapheme_len;
22620            }
22621            WordBreakToken::InlineWhitespace {
22622                mut token,
22623                mut grapheme_len,
22624            } => {
22625                in_whitespace = true;
22626                if have_preceding_whitespace && !preserve_existing_whitespace {
22627                    continue;
22628                }
22629                if !preserve_existing_whitespace {
22630                    // Keep a single whitespace grapheme as-is
22631                    if let Some(first) =
22632                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22633                    {
22634                        token = first;
22635                    } else {
22636                        token = " ";
22637                    }
22638                    grapheme_len = 1;
22639                }
22640                let current_prefix_len = if is_first_line {
22641                    first_line_prefix_len
22642                } else {
22643                    subsequent_lines_prefix_len
22644                };
22645                if current_line_len + grapheme_len > wrap_column {
22646                    wrapped_text.push_str(current_line.trim_end());
22647                    wrapped_text.push('\n');
22648                    is_first_line = false;
22649                    current_line = subsequent_lines_prefix.clone();
22650                    current_line_len = subsequent_lines_prefix_len;
22651                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22652                    current_line.push_str(token);
22653                    current_line_len += grapheme_len;
22654                }
22655            }
22656            WordBreakToken::Newline => {
22657                in_whitespace = true;
22658                let current_prefix_len = if is_first_line {
22659                    first_line_prefix_len
22660                } else {
22661                    subsequent_lines_prefix_len
22662                };
22663                if preserve_existing_whitespace {
22664                    wrapped_text.push_str(current_line.trim_end());
22665                    wrapped_text.push('\n');
22666                    is_first_line = false;
22667                    current_line = subsequent_lines_prefix.clone();
22668                    current_line_len = subsequent_lines_prefix_len;
22669                } else if have_preceding_whitespace {
22670                    continue;
22671                } else if current_line_len + 1 > wrap_column
22672                    && current_line_len != current_prefix_len
22673                {
22674                    wrapped_text.push_str(current_line.trim_end());
22675                    wrapped_text.push('\n');
22676                    is_first_line = false;
22677                    current_line = subsequent_lines_prefix.clone();
22678                    current_line_len = subsequent_lines_prefix_len;
22679                } else if current_line_len != current_prefix_len {
22680                    current_line.push(' ');
22681                    current_line_len += 1;
22682                }
22683            }
22684        }
22685    }
22686
22687    if !current_line.is_empty() {
22688        wrapped_text.push_str(&current_line);
22689    }
22690    wrapped_text
22691}
22692
22693#[test]
22694fn test_wrap_with_prefix() {
22695    assert_eq!(
22696        wrap_with_prefix(
22697            "# ".to_string(),
22698            "# ".to_string(),
22699            "abcdefg".to_string(),
22700            4,
22701            NonZeroU32::new(4).unwrap(),
22702            false,
22703        ),
22704        "# abcdefg"
22705    );
22706    assert_eq!(
22707        wrap_with_prefix(
22708            "".to_string(),
22709            "".to_string(),
22710            "\thello world".to_string(),
22711            8,
22712            NonZeroU32::new(4).unwrap(),
22713            false,
22714        ),
22715        "hello\nworld"
22716    );
22717    assert_eq!(
22718        wrap_with_prefix(
22719            "// ".to_string(),
22720            "// ".to_string(),
22721            "xx \nyy zz aa bb cc".to_string(),
22722            12,
22723            NonZeroU32::new(4).unwrap(),
22724            false,
22725        ),
22726        "// xx yy zz\n// aa bb cc"
22727    );
22728    assert_eq!(
22729        wrap_with_prefix(
22730            String::new(),
22731            String::new(),
22732            "这是什么 \n 钢笔".to_string(),
22733            3,
22734            NonZeroU32::new(4).unwrap(),
22735            false,
22736        ),
22737        "这是什\n么 钢\n"
22738    );
22739    assert_eq!(
22740        wrap_with_prefix(
22741            String::new(),
22742            String::new(),
22743            format!("foo{}bar", '\u{2009}'), // thin space
22744            80,
22745            NonZeroU32::new(4).unwrap(),
22746            false,
22747        ),
22748        format!("foo{}bar", '\u{2009}')
22749    );
22750}
22751
22752pub trait CollaborationHub {
22753    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22754    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22755    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22756}
22757
22758impl CollaborationHub for Entity<Project> {
22759    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22760        self.read(cx).collaborators()
22761    }
22762
22763    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22764        self.read(cx).user_store().read(cx).participant_indices()
22765    }
22766
22767    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22768        let this = self.read(cx);
22769        let user_ids = this.collaborators().values().map(|c| c.user_id);
22770        this.user_store().read(cx).participant_names(user_ids, cx)
22771    }
22772}
22773
22774pub trait SemanticsProvider {
22775    fn hover(
22776        &self,
22777        buffer: &Entity<Buffer>,
22778        position: text::Anchor,
22779        cx: &mut App,
22780    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22781
22782    fn inline_values(
22783        &self,
22784        buffer_handle: Entity<Buffer>,
22785        range: Range<text::Anchor>,
22786        cx: &mut App,
22787    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22788
22789    fn applicable_inlay_chunks(
22790        &self,
22791        buffer: &Entity<Buffer>,
22792        ranges: &[Range<text::Anchor>],
22793        cx: &mut App,
22794    ) -> Vec<Range<BufferRow>>;
22795
22796    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22797
22798    fn inlay_hints(
22799        &self,
22800        invalidate: InvalidationStrategy,
22801        buffer: Entity<Buffer>,
22802        ranges: Vec<Range<text::Anchor>>,
22803        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22804        cx: &mut App,
22805    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22806
22807    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22808
22809    fn document_highlights(
22810        &self,
22811        buffer: &Entity<Buffer>,
22812        position: text::Anchor,
22813        cx: &mut App,
22814    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22815
22816    fn definitions(
22817        &self,
22818        buffer: &Entity<Buffer>,
22819        position: text::Anchor,
22820        kind: GotoDefinitionKind,
22821        cx: &mut App,
22822    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22823
22824    fn range_for_rename(
22825        &self,
22826        buffer: &Entity<Buffer>,
22827        position: text::Anchor,
22828        cx: &mut App,
22829    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22830
22831    fn perform_rename(
22832        &self,
22833        buffer: &Entity<Buffer>,
22834        position: text::Anchor,
22835        new_name: String,
22836        cx: &mut App,
22837    ) -> Option<Task<Result<ProjectTransaction>>>;
22838}
22839
22840pub trait CompletionProvider {
22841    fn completions(
22842        &self,
22843        excerpt_id: ExcerptId,
22844        buffer: &Entity<Buffer>,
22845        buffer_position: text::Anchor,
22846        trigger: CompletionContext,
22847        window: &mut Window,
22848        cx: &mut Context<Editor>,
22849    ) -> Task<Result<Vec<CompletionResponse>>>;
22850
22851    fn resolve_completions(
22852        &self,
22853        _buffer: Entity<Buffer>,
22854        _completion_indices: Vec<usize>,
22855        _completions: Rc<RefCell<Box<[Completion]>>>,
22856        _cx: &mut Context<Editor>,
22857    ) -> Task<Result<bool>> {
22858        Task::ready(Ok(false))
22859    }
22860
22861    fn apply_additional_edits_for_completion(
22862        &self,
22863        _buffer: Entity<Buffer>,
22864        _completions: Rc<RefCell<Box<[Completion]>>>,
22865        _completion_index: usize,
22866        _push_to_history: bool,
22867        _cx: &mut Context<Editor>,
22868    ) -> Task<Result<Option<language::Transaction>>> {
22869        Task::ready(Ok(None))
22870    }
22871
22872    fn is_completion_trigger(
22873        &self,
22874        buffer: &Entity<Buffer>,
22875        position: language::Anchor,
22876        text: &str,
22877        trigger_in_words: bool,
22878        menu_is_open: bool,
22879        cx: &mut Context<Editor>,
22880    ) -> bool;
22881
22882    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22883
22884    fn sort_completions(&self) -> bool {
22885        true
22886    }
22887
22888    fn filter_completions(&self) -> bool {
22889        true
22890    }
22891}
22892
22893pub trait CodeActionProvider {
22894    fn id(&self) -> Arc<str>;
22895
22896    fn code_actions(
22897        &self,
22898        buffer: &Entity<Buffer>,
22899        range: Range<text::Anchor>,
22900        window: &mut Window,
22901        cx: &mut App,
22902    ) -> Task<Result<Vec<CodeAction>>>;
22903
22904    fn apply_code_action(
22905        &self,
22906        buffer_handle: Entity<Buffer>,
22907        action: CodeAction,
22908        excerpt_id: ExcerptId,
22909        push_to_history: bool,
22910        window: &mut Window,
22911        cx: &mut App,
22912    ) -> Task<Result<ProjectTransaction>>;
22913}
22914
22915impl CodeActionProvider for Entity<Project> {
22916    fn id(&self) -> Arc<str> {
22917        "project".into()
22918    }
22919
22920    fn code_actions(
22921        &self,
22922        buffer: &Entity<Buffer>,
22923        range: Range<text::Anchor>,
22924        _window: &mut Window,
22925        cx: &mut App,
22926    ) -> Task<Result<Vec<CodeAction>>> {
22927        self.update(cx, |project, cx| {
22928            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22929            let code_actions = project.code_actions(buffer, range, None, cx);
22930            cx.background_spawn(async move {
22931                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22932                Ok(code_lens_actions
22933                    .context("code lens fetch")?
22934                    .into_iter()
22935                    .flatten()
22936                    .chain(
22937                        code_actions
22938                            .context("code action fetch")?
22939                            .into_iter()
22940                            .flatten(),
22941                    )
22942                    .collect())
22943            })
22944        })
22945    }
22946
22947    fn apply_code_action(
22948        &self,
22949        buffer_handle: Entity<Buffer>,
22950        action: CodeAction,
22951        _excerpt_id: ExcerptId,
22952        push_to_history: bool,
22953        _window: &mut Window,
22954        cx: &mut App,
22955    ) -> Task<Result<ProjectTransaction>> {
22956        self.update(cx, |project, cx| {
22957            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22958        })
22959    }
22960}
22961
22962fn snippet_completions(
22963    project: &Project,
22964    buffer: &Entity<Buffer>,
22965    buffer_position: text::Anchor,
22966    cx: &mut App,
22967) -> Task<Result<CompletionResponse>> {
22968    let languages = buffer.read(cx).languages_at(buffer_position);
22969    let snippet_store = project.snippets().read(cx);
22970
22971    let scopes: Vec<_> = languages
22972        .iter()
22973        .filter_map(|language| {
22974            let language_name = language.lsp_id();
22975            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22976
22977            if snippets.is_empty() {
22978                None
22979            } else {
22980                Some((language.default_scope(), snippets))
22981            }
22982        })
22983        .collect();
22984
22985    if scopes.is_empty() {
22986        return Task::ready(Ok(CompletionResponse {
22987            completions: vec![],
22988            display_options: CompletionDisplayOptions::default(),
22989            is_incomplete: false,
22990        }));
22991    }
22992
22993    let snapshot = buffer.read(cx).text_snapshot();
22994    let executor = cx.background_executor().clone();
22995
22996    cx.background_spawn(async move {
22997        let mut is_incomplete = false;
22998        let mut completions: Vec<Completion> = Vec::new();
22999        for (scope, snippets) in scopes.into_iter() {
23000            let classifier =
23001                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23002
23003            const MAX_WORD_PREFIX_LEN: usize = 128;
23004            let last_word: String = snapshot
23005                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23006                .take(MAX_WORD_PREFIX_LEN)
23007                .take_while(|c| classifier.is_word(*c))
23008                .collect::<String>()
23009                .chars()
23010                .rev()
23011                .collect();
23012
23013            if last_word.is_empty() {
23014                return Ok(CompletionResponse {
23015                    completions: vec![],
23016                    display_options: CompletionDisplayOptions::default(),
23017                    is_incomplete: true,
23018                });
23019            }
23020
23021            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23022            let to_lsp = |point: &text::Anchor| {
23023                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23024                point_to_lsp(end)
23025            };
23026            let lsp_end = to_lsp(&buffer_position);
23027
23028            let candidates = snippets
23029                .iter()
23030                .enumerate()
23031                .flat_map(|(ix, snippet)| {
23032                    snippet
23033                        .prefix
23034                        .iter()
23035                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23036                })
23037                .collect::<Vec<StringMatchCandidate>>();
23038
23039            const MAX_RESULTS: usize = 100;
23040            let mut matches = fuzzy::match_strings(
23041                &candidates,
23042                &last_word,
23043                last_word.chars().any(|c| c.is_uppercase()),
23044                true,
23045                MAX_RESULTS,
23046                &Default::default(),
23047                executor.clone(),
23048            )
23049            .await;
23050
23051            if matches.len() >= MAX_RESULTS {
23052                is_incomplete = true;
23053            }
23054
23055            // Remove all candidates where the query's start does not match the start of any word in the candidate
23056            if let Some(query_start) = last_word.chars().next() {
23057                matches.retain(|string_match| {
23058                    split_words(&string_match.string).any(|word| {
23059                        // Check that the first codepoint of the word as lowercase matches the first
23060                        // codepoint of the query as lowercase
23061                        word.chars()
23062                            .flat_map(|codepoint| codepoint.to_lowercase())
23063                            .zip(query_start.to_lowercase())
23064                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23065                    })
23066                });
23067            }
23068
23069            let matched_strings = matches
23070                .into_iter()
23071                .map(|m| m.string)
23072                .collect::<HashSet<_>>();
23073
23074            completions.extend(snippets.iter().filter_map(|snippet| {
23075                let matching_prefix = snippet
23076                    .prefix
23077                    .iter()
23078                    .find(|prefix| matched_strings.contains(*prefix))?;
23079                let start = as_offset - last_word.len();
23080                let start = snapshot.anchor_before(start);
23081                let range = start..buffer_position;
23082                let lsp_start = to_lsp(&start);
23083                let lsp_range = lsp::Range {
23084                    start: lsp_start,
23085                    end: lsp_end,
23086                };
23087                Some(Completion {
23088                    replace_range: range,
23089                    new_text: snippet.body.clone(),
23090                    source: CompletionSource::Lsp {
23091                        insert_range: None,
23092                        server_id: LanguageServerId(usize::MAX),
23093                        resolved: true,
23094                        lsp_completion: Box::new(lsp::CompletionItem {
23095                            label: snippet.prefix.first().unwrap().clone(),
23096                            kind: Some(CompletionItemKind::SNIPPET),
23097                            label_details: snippet.description.as_ref().map(|description| {
23098                                lsp::CompletionItemLabelDetails {
23099                                    detail: Some(description.clone()),
23100                                    description: None,
23101                                }
23102                            }),
23103                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23104                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23105                                lsp::InsertReplaceEdit {
23106                                    new_text: snippet.body.clone(),
23107                                    insert: lsp_range,
23108                                    replace: lsp_range,
23109                                },
23110                            )),
23111                            filter_text: Some(snippet.body.clone()),
23112                            sort_text: Some(char::MAX.to_string()),
23113                            ..lsp::CompletionItem::default()
23114                        }),
23115                        lsp_defaults: None,
23116                    },
23117                    label: CodeLabel::plain(matching_prefix.clone(), None),
23118                    icon_path: None,
23119                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23120                        single_line: snippet.name.clone().into(),
23121                        plain_text: snippet
23122                            .description
23123                            .clone()
23124                            .map(|description| description.into()),
23125                    }),
23126                    insert_text_mode: None,
23127                    confirm: None,
23128                })
23129            }))
23130        }
23131
23132        Ok(CompletionResponse {
23133            completions,
23134            display_options: CompletionDisplayOptions::default(),
23135            is_incomplete,
23136        })
23137    })
23138}
23139
23140impl CompletionProvider for Entity<Project> {
23141    fn completions(
23142        &self,
23143        _excerpt_id: ExcerptId,
23144        buffer: &Entity<Buffer>,
23145        buffer_position: text::Anchor,
23146        options: CompletionContext,
23147        _window: &mut Window,
23148        cx: &mut Context<Editor>,
23149    ) -> Task<Result<Vec<CompletionResponse>>> {
23150        self.update(cx, |project, cx| {
23151            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23152            let project_completions = project.completions(buffer, buffer_position, options, cx);
23153            cx.background_spawn(async move {
23154                let mut responses = project_completions.await?;
23155                let snippets = snippets.await?;
23156                if !snippets.completions.is_empty() {
23157                    responses.push(snippets);
23158                }
23159                Ok(responses)
23160            })
23161        })
23162    }
23163
23164    fn resolve_completions(
23165        &self,
23166        buffer: Entity<Buffer>,
23167        completion_indices: Vec<usize>,
23168        completions: Rc<RefCell<Box<[Completion]>>>,
23169        cx: &mut Context<Editor>,
23170    ) -> Task<Result<bool>> {
23171        self.update(cx, |project, cx| {
23172            project.lsp_store().update(cx, |lsp_store, cx| {
23173                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23174            })
23175        })
23176    }
23177
23178    fn apply_additional_edits_for_completion(
23179        &self,
23180        buffer: Entity<Buffer>,
23181        completions: Rc<RefCell<Box<[Completion]>>>,
23182        completion_index: usize,
23183        push_to_history: bool,
23184        cx: &mut Context<Editor>,
23185    ) -> Task<Result<Option<language::Transaction>>> {
23186        self.update(cx, |project, cx| {
23187            project.lsp_store().update(cx, |lsp_store, cx| {
23188                lsp_store.apply_additional_edits_for_completion(
23189                    buffer,
23190                    completions,
23191                    completion_index,
23192                    push_to_history,
23193                    cx,
23194                )
23195            })
23196        })
23197    }
23198
23199    fn is_completion_trigger(
23200        &self,
23201        buffer: &Entity<Buffer>,
23202        position: language::Anchor,
23203        text: &str,
23204        trigger_in_words: bool,
23205        menu_is_open: bool,
23206        cx: &mut Context<Editor>,
23207    ) -> bool {
23208        let mut chars = text.chars();
23209        let char = if let Some(char) = chars.next() {
23210            char
23211        } else {
23212            return false;
23213        };
23214        if chars.next().is_some() {
23215            return false;
23216        }
23217
23218        let buffer = buffer.read(cx);
23219        let snapshot = buffer.snapshot();
23220        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23221            return false;
23222        }
23223        let classifier = snapshot
23224            .char_classifier_at(position)
23225            .scope_context(Some(CharScopeContext::Completion));
23226        if trigger_in_words && classifier.is_word(char) {
23227            return true;
23228        }
23229
23230        buffer.completion_triggers().contains(text)
23231    }
23232}
23233
23234impl SemanticsProvider for Entity<Project> {
23235    fn hover(
23236        &self,
23237        buffer: &Entity<Buffer>,
23238        position: text::Anchor,
23239        cx: &mut App,
23240    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23241        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23242    }
23243
23244    fn document_highlights(
23245        &self,
23246        buffer: &Entity<Buffer>,
23247        position: text::Anchor,
23248        cx: &mut App,
23249    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23250        Some(self.update(cx, |project, cx| {
23251            project.document_highlights(buffer, position, cx)
23252        }))
23253    }
23254
23255    fn definitions(
23256        &self,
23257        buffer: &Entity<Buffer>,
23258        position: text::Anchor,
23259        kind: GotoDefinitionKind,
23260        cx: &mut App,
23261    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23262        Some(self.update(cx, |project, cx| match kind {
23263            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23264            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23265            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23266            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23267        }))
23268    }
23269
23270    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23271        self.update(cx, |project, cx| {
23272            if project
23273                .active_debug_session(cx)
23274                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23275            {
23276                return true;
23277            }
23278
23279            buffer.update(cx, |buffer, cx| {
23280                project.any_language_server_supports_inlay_hints(buffer, cx)
23281            })
23282        })
23283    }
23284
23285    fn inline_values(
23286        &self,
23287        buffer_handle: Entity<Buffer>,
23288        range: Range<text::Anchor>,
23289        cx: &mut App,
23290    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23291        self.update(cx, |project, cx| {
23292            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23293
23294            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23295        })
23296    }
23297
23298    fn applicable_inlay_chunks(
23299        &self,
23300        buffer: &Entity<Buffer>,
23301        ranges: &[Range<text::Anchor>],
23302        cx: &mut App,
23303    ) -> Vec<Range<BufferRow>> {
23304        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23305            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23306        })
23307    }
23308
23309    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23310        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23311            lsp_store.invalidate_inlay_hints(for_buffers)
23312        });
23313    }
23314
23315    fn inlay_hints(
23316        &self,
23317        invalidate: InvalidationStrategy,
23318        buffer: Entity<Buffer>,
23319        ranges: Vec<Range<text::Anchor>>,
23320        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23321        cx: &mut App,
23322    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23323        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23324            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23325        }))
23326    }
23327
23328    fn range_for_rename(
23329        &self,
23330        buffer: &Entity<Buffer>,
23331        position: text::Anchor,
23332        cx: &mut App,
23333    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23334        Some(self.update(cx, |project, cx| {
23335            let buffer = buffer.clone();
23336            let task = project.prepare_rename(buffer.clone(), position, cx);
23337            cx.spawn(async move |_, cx| {
23338                Ok(match task.await? {
23339                    PrepareRenameResponse::Success(range) => Some(range),
23340                    PrepareRenameResponse::InvalidPosition => None,
23341                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23342                        // Fallback on using TreeSitter info to determine identifier range
23343                        buffer.read_with(cx, |buffer, _| {
23344                            let snapshot = buffer.snapshot();
23345                            let (range, kind) = snapshot.surrounding_word(position, None);
23346                            if kind != Some(CharKind::Word) {
23347                                return None;
23348                            }
23349                            Some(
23350                                snapshot.anchor_before(range.start)
23351                                    ..snapshot.anchor_after(range.end),
23352                            )
23353                        })?
23354                    }
23355                })
23356            })
23357        }))
23358    }
23359
23360    fn perform_rename(
23361        &self,
23362        buffer: &Entity<Buffer>,
23363        position: text::Anchor,
23364        new_name: String,
23365        cx: &mut App,
23366    ) -> Option<Task<Result<ProjectTransaction>>> {
23367        Some(self.update(cx, |project, cx| {
23368            project.perform_rename(buffer.clone(), position, new_name, cx)
23369        }))
23370    }
23371}
23372
23373fn consume_contiguous_rows(
23374    contiguous_row_selections: &mut Vec<Selection<Point>>,
23375    selection: &Selection<Point>,
23376    display_map: &DisplaySnapshot,
23377    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23378) -> (MultiBufferRow, MultiBufferRow) {
23379    contiguous_row_selections.push(selection.clone());
23380    let start_row = starting_row(selection, display_map);
23381    let mut end_row = ending_row(selection, display_map);
23382
23383    while let Some(next_selection) = selections.peek() {
23384        if next_selection.start.row <= end_row.0 {
23385            end_row = ending_row(next_selection, display_map);
23386            contiguous_row_selections.push(selections.next().unwrap().clone());
23387        } else {
23388            break;
23389        }
23390    }
23391    (start_row, end_row)
23392}
23393
23394fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23395    if selection.start.column > 0 {
23396        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23397    } else {
23398        MultiBufferRow(selection.start.row)
23399    }
23400}
23401
23402fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23403    if next_selection.end.column > 0 || next_selection.is_empty() {
23404        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23405    } else {
23406        MultiBufferRow(next_selection.end.row)
23407    }
23408}
23409
23410impl EditorSnapshot {
23411    pub fn remote_selections_in_range<'a>(
23412        &'a self,
23413        range: &'a Range<Anchor>,
23414        collaboration_hub: &dyn CollaborationHub,
23415        cx: &'a App,
23416    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23417        let participant_names = collaboration_hub.user_names(cx);
23418        let participant_indices = collaboration_hub.user_participant_indices(cx);
23419        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23420        let collaborators_by_replica_id = collaborators_by_peer_id
23421            .values()
23422            .map(|collaborator| (collaborator.replica_id, collaborator))
23423            .collect::<HashMap<_, _>>();
23424        self.buffer_snapshot()
23425            .selections_in_range(range, false)
23426            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23427                if replica_id == ReplicaId::AGENT {
23428                    Some(RemoteSelection {
23429                        replica_id,
23430                        selection,
23431                        cursor_shape,
23432                        line_mode,
23433                        collaborator_id: CollaboratorId::Agent,
23434                        user_name: Some("Agent".into()),
23435                        color: cx.theme().players().agent(),
23436                    })
23437                } else {
23438                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23439                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23440                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23441                    Some(RemoteSelection {
23442                        replica_id,
23443                        selection,
23444                        cursor_shape,
23445                        line_mode,
23446                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23447                        user_name,
23448                        color: if let Some(index) = participant_index {
23449                            cx.theme().players().color_for_participant(index.0)
23450                        } else {
23451                            cx.theme().players().absent()
23452                        },
23453                    })
23454                }
23455            })
23456    }
23457
23458    pub fn hunks_for_ranges(
23459        &self,
23460        ranges: impl IntoIterator<Item = Range<Point>>,
23461    ) -> Vec<MultiBufferDiffHunk> {
23462        let mut hunks = Vec::new();
23463        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23464            HashMap::default();
23465        for query_range in ranges {
23466            let query_rows =
23467                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23468            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23469                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23470            ) {
23471                // Include deleted hunks that are adjacent to the query range, because
23472                // otherwise they would be missed.
23473                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23474                if hunk.status().is_deleted() {
23475                    intersects_range |= hunk.row_range.start == query_rows.end;
23476                    intersects_range |= hunk.row_range.end == query_rows.start;
23477                }
23478                if intersects_range {
23479                    if !processed_buffer_rows
23480                        .entry(hunk.buffer_id)
23481                        .or_default()
23482                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23483                    {
23484                        continue;
23485                    }
23486                    hunks.push(hunk);
23487                }
23488            }
23489        }
23490
23491        hunks
23492    }
23493
23494    fn display_diff_hunks_for_rows<'a>(
23495        &'a self,
23496        display_rows: Range<DisplayRow>,
23497        folded_buffers: &'a HashSet<BufferId>,
23498    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23499        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23500        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23501
23502        self.buffer_snapshot()
23503            .diff_hunks_in_range(buffer_start..buffer_end)
23504            .filter_map(|hunk| {
23505                if folded_buffers.contains(&hunk.buffer_id) {
23506                    return None;
23507                }
23508
23509                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23510                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23511
23512                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23513                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23514
23515                let display_hunk = if hunk_display_start.column() != 0 {
23516                    DisplayDiffHunk::Folded {
23517                        display_row: hunk_display_start.row(),
23518                    }
23519                } else {
23520                    let mut end_row = hunk_display_end.row();
23521                    if hunk_display_end.column() > 0 {
23522                        end_row.0 += 1;
23523                    }
23524                    let is_created_file = hunk.is_created_file();
23525                    DisplayDiffHunk::Unfolded {
23526                        status: hunk.status(),
23527                        diff_base_byte_range: hunk.diff_base_byte_range,
23528                        display_row_range: hunk_display_start.row()..end_row,
23529                        multi_buffer_range: Anchor::range_in_buffer(
23530                            hunk.excerpt_id,
23531                            hunk.buffer_id,
23532                            hunk.buffer_range,
23533                        ),
23534                        is_created_file,
23535                    }
23536                };
23537
23538                Some(display_hunk)
23539            })
23540    }
23541
23542    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23543        self.display_snapshot
23544            .buffer_snapshot()
23545            .language_at(position)
23546    }
23547
23548    pub fn is_focused(&self) -> bool {
23549        self.is_focused
23550    }
23551
23552    pub fn placeholder_text(&self) -> Option<String> {
23553        self.placeholder_display_snapshot
23554            .as_ref()
23555            .map(|display_map| display_map.text())
23556    }
23557
23558    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23559        self.scroll_anchor.scroll_position(&self.display_snapshot)
23560    }
23561
23562    fn gutter_dimensions(
23563        &self,
23564        font_id: FontId,
23565        font_size: Pixels,
23566        max_line_number_width: Pixels,
23567        cx: &App,
23568    ) -> Option<GutterDimensions> {
23569        if !self.show_gutter {
23570            return None;
23571        }
23572
23573        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23574        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23575
23576        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23577            matches!(
23578                ProjectSettings::get_global(cx).git.git_gutter,
23579                GitGutterSetting::TrackedFiles
23580            )
23581        });
23582        let gutter_settings = EditorSettings::get_global(cx).gutter;
23583        let show_line_numbers = self
23584            .show_line_numbers
23585            .unwrap_or(gutter_settings.line_numbers);
23586        let line_gutter_width = if show_line_numbers {
23587            // Avoid flicker-like gutter resizes when the line number gains another digit by
23588            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23589            let min_width_for_number_on_gutter =
23590                ch_advance * gutter_settings.min_line_number_digits as f32;
23591            max_line_number_width.max(min_width_for_number_on_gutter)
23592        } else {
23593            0.0.into()
23594        };
23595
23596        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23597        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23598
23599        let git_blame_entries_width =
23600            self.git_blame_gutter_max_author_length
23601                .map(|max_author_length| {
23602                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23603                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23604
23605                    /// The number of characters to dedicate to gaps and margins.
23606                    const SPACING_WIDTH: usize = 4;
23607
23608                    let max_char_count = max_author_length.min(renderer.max_author_length())
23609                        + ::git::SHORT_SHA_LENGTH
23610                        + MAX_RELATIVE_TIMESTAMP.len()
23611                        + SPACING_WIDTH;
23612
23613                    ch_advance * max_char_count
23614                });
23615
23616        let is_singleton = self.buffer_snapshot().is_singleton();
23617
23618        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23619        left_padding += if !is_singleton {
23620            ch_width * 4.0
23621        } else if show_runnables || show_breakpoints {
23622            ch_width * 3.0
23623        } else if show_git_gutter && show_line_numbers {
23624            ch_width * 2.0
23625        } else if show_git_gutter || show_line_numbers {
23626            ch_width
23627        } else {
23628            px(0.)
23629        };
23630
23631        let shows_folds = is_singleton && gutter_settings.folds;
23632
23633        let right_padding = if shows_folds && show_line_numbers {
23634            ch_width * 4.0
23635        } else if shows_folds || (!is_singleton && show_line_numbers) {
23636            ch_width * 3.0
23637        } else if show_line_numbers {
23638            ch_width
23639        } else {
23640            px(0.)
23641        };
23642
23643        Some(GutterDimensions {
23644            left_padding,
23645            right_padding,
23646            width: line_gutter_width + left_padding + right_padding,
23647            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23648            git_blame_entries_width,
23649        })
23650    }
23651
23652    pub fn render_crease_toggle(
23653        &self,
23654        buffer_row: MultiBufferRow,
23655        row_contains_cursor: bool,
23656        editor: Entity<Editor>,
23657        window: &mut Window,
23658        cx: &mut App,
23659    ) -> Option<AnyElement> {
23660        let folded = self.is_line_folded(buffer_row);
23661        let mut is_foldable = false;
23662
23663        if let Some(crease) = self
23664            .crease_snapshot
23665            .query_row(buffer_row, self.buffer_snapshot())
23666        {
23667            is_foldable = true;
23668            match crease {
23669                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23670                    if let Some(render_toggle) = render_toggle {
23671                        let toggle_callback =
23672                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23673                                if folded {
23674                                    editor.update(cx, |editor, cx| {
23675                                        editor.fold_at(buffer_row, window, cx)
23676                                    });
23677                                } else {
23678                                    editor.update(cx, |editor, cx| {
23679                                        editor.unfold_at(buffer_row, window, cx)
23680                                    });
23681                                }
23682                            });
23683                        return Some((render_toggle)(
23684                            buffer_row,
23685                            folded,
23686                            toggle_callback,
23687                            window,
23688                            cx,
23689                        ));
23690                    }
23691                }
23692            }
23693        }
23694
23695        is_foldable |= self.starts_indent(buffer_row);
23696
23697        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23698            Some(
23699                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23700                    .toggle_state(folded)
23701                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23702                        if folded {
23703                            this.unfold_at(buffer_row, window, cx);
23704                        } else {
23705                            this.fold_at(buffer_row, window, cx);
23706                        }
23707                    }))
23708                    .into_any_element(),
23709            )
23710        } else {
23711            None
23712        }
23713    }
23714
23715    pub fn render_crease_trailer(
23716        &self,
23717        buffer_row: MultiBufferRow,
23718        window: &mut Window,
23719        cx: &mut App,
23720    ) -> Option<AnyElement> {
23721        let folded = self.is_line_folded(buffer_row);
23722        if let Crease::Inline { render_trailer, .. } = self
23723            .crease_snapshot
23724            .query_row(buffer_row, self.buffer_snapshot())?
23725        {
23726            let render_trailer = render_trailer.as_ref()?;
23727            Some(render_trailer(buffer_row, folded, window, cx))
23728        } else {
23729            None
23730        }
23731    }
23732}
23733
23734impl Deref for EditorSnapshot {
23735    type Target = DisplaySnapshot;
23736
23737    fn deref(&self) -> &Self::Target {
23738        &self.display_snapshot
23739    }
23740}
23741
23742#[derive(Clone, Debug, PartialEq, Eq)]
23743pub enum EditorEvent {
23744    InputIgnored {
23745        text: Arc<str>,
23746    },
23747    InputHandled {
23748        utf16_range_to_replace: Option<Range<isize>>,
23749        text: Arc<str>,
23750    },
23751    ExcerptsAdded {
23752        buffer: Entity<Buffer>,
23753        predecessor: ExcerptId,
23754        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23755    },
23756    ExcerptsRemoved {
23757        ids: Vec<ExcerptId>,
23758        removed_buffer_ids: Vec<BufferId>,
23759    },
23760    BufferFoldToggled {
23761        ids: Vec<ExcerptId>,
23762        folded: bool,
23763    },
23764    ExcerptsEdited {
23765        ids: Vec<ExcerptId>,
23766    },
23767    ExcerptsExpanded {
23768        ids: Vec<ExcerptId>,
23769    },
23770    BufferEdited,
23771    Edited {
23772        transaction_id: clock::Lamport,
23773    },
23774    Reparsed(BufferId),
23775    Focused,
23776    FocusedIn,
23777    Blurred,
23778    DirtyChanged,
23779    Saved,
23780    TitleChanged,
23781    SelectionsChanged {
23782        local: bool,
23783    },
23784    ScrollPositionChanged {
23785        local: bool,
23786        autoscroll: bool,
23787    },
23788    TransactionUndone {
23789        transaction_id: clock::Lamport,
23790    },
23791    TransactionBegun {
23792        transaction_id: clock::Lamport,
23793    },
23794    CursorShapeChanged,
23795    BreadcrumbsChanged,
23796    PushedToNavHistory {
23797        anchor: Anchor,
23798        is_deactivate: bool,
23799    },
23800}
23801
23802impl EventEmitter<EditorEvent> for Editor {}
23803
23804impl Focusable for Editor {
23805    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23806        self.focus_handle.clone()
23807    }
23808}
23809
23810impl Render for Editor {
23811    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23812        let settings = ThemeSettings::get_global(cx);
23813
23814        let mut text_style = match self.mode {
23815            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23816                color: cx.theme().colors().editor_foreground,
23817                font_family: settings.ui_font.family.clone(),
23818                font_features: settings.ui_font.features.clone(),
23819                font_fallbacks: settings.ui_font.fallbacks.clone(),
23820                font_size: rems(0.875).into(),
23821                font_weight: settings.ui_font.weight,
23822                line_height: relative(settings.buffer_line_height.value()),
23823                ..Default::default()
23824            },
23825            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23826                color: cx.theme().colors().editor_foreground,
23827                font_family: settings.buffer_font.family.clone(),
23828                font_features: settings.buffer_font.features.clone(),
23829                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23830                font_size: settings.buffer_font_size(cx).into(),
23831                font_weight: settings.buffer_font.weight,
23832                line_height: relative(settings.buffer_line_height.value()),
23833                ..Default::default()
23834            },
23835        };
23836        if let Some(text_style_refinement) = &self.text_style_refinement {
23837            text_style.refine(text_style_refinement)
23838        }
23839
23840        let background = match self.mode {
23841            EditorMode::SingleLine => cx.theme().system().transparent,
23842            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23843            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23844            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23845        };
23846
23847        EditorElement::new(
23848            &cx.entity(),
23849            EditorStyle {
23850                background,
23851                border: cx.theme().colors().border,
23852                local_player: cx.theme().players().local(),
23853                text: text_style,
23854                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23855                syntax: cx.theme().syntax().clone(),
23856                status: cx.theme().status().clone(),
23857                inlay_hints_style: make_inlay_hints_style(cx),
23858                edit_prediction_styles: make_suggestion_styles(cx),
23859                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23860                show_underlines: self.diagnostics_enabled(),
23861            },
23862        )
23863    }
23864}
23865
23866impl EntityInputHandler for Editor {
23867    fn text_for_range(
23868        &mut self,
23869        range_utf16: Range<usize>,
23870        adjusted_range: &mut Option<Range<usize>>,
23871        _: &mut Window,
23872        cx: &mut Context<Self>,
23873    ) -> Option<String> {
23874        let snapshot = self.buffer.read(cx).read(cx);
23875        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23876        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23877        if (start.0..end.0) != range_utf16 {
23878            adjusted_range.replace(start.0..end.0);
23879        }
23880        Some(snapshot.text_for_range(start..end).collect())
23881    }
23882
23883    fn selected_text_range(
23884        &mut self,
23885        ignore_disabled_input: bool,
23886        _: &mut Window,
23887        cx: &mut Context<Self>,
23888    ) -> Option<UTF16Selection> {
23889        // Prevent the IME menu from appearing when holding down an alphabetic key
23890        // while input is disabled.
23891        if !ignore_disabled_input && !self.input_enabled {
23892            return None;
23893        }
23894
23895        let selection = self
23896            .selections
23897            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23898        let range = selection.range();
23899
23900        Some(UTF16Selection {
23901            range: range.start.0..range.end.0,
23902            reversed: selection.reversed,
23903        })
23904    }
23905
23906    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23907        let snapshot = self.buffer.read(cx).read(cx);
23908        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23909        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23910    }
23911
23912    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23913        self.clear_highlights::<InputComposition>(cx);
23914        self.ime_transaction.take();
23915    }
23916
23917    fn replace_text_in_range(
23918        &mut self,
23919        range_utf16: Option<Range<usize>>,
23920        text: &str,
23921        window: &mut Window,
23922        cx: &mut Context<Self>,
23923    ) {
23924        if !self.input_enabled {
23925            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23926            return;
23927        }
23928
23929        self.transact(window, cx, |this, window, cx| {
23930            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23931                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23932                Some(this.selection_replacement_ranges(range_utf16, cx))
23933            } else {
23934                this.marked_text_ranges(cx)
23935            };
23936
23937            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23938                let newest_selection_id = this.selections.newest_anchor().id;
23939                this.selections
23940                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23941                    .iter()
23942                    .zip(ranges_to_replace.iter())
23943                    .find_map(|(selection, range)| {
23944                        if selection.id == newest_selection_id {
23945                            Some(
23946                                (range.start.0 as isize - selection.head().0 as isize)
23947                                    ..(range.end.0 as isize - selection.head().0 as isize),
23948                            )
23949                        } else {
23950                            None
23951                        }
23952                    })
23953            });
23954
23955            cx.emit(EditorEvent::InputHandled {
23956                utf16_range_to_replace: range_to_replace,
23957                text: text.into(),
23958            });
23959
23960            if let Some(new_selected_ranges) = new_selected_ranges {
23961                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23962                    selections.select_ranges(new_selected_ranges)
23963                });
23964                this.backspace(&Default::default(), window, cx);
23965            }
23966
23967            this.handle_input(text, window, cx);
23968        });
23969
23970        if let Some(transaction) = self.ime_transaction {
23971            self.buffer.update(cx, |buffer, cx| {
23972                buffer.group_until_transaction(transaction, cx);
23973            });
23974        }
23975
23976        self.unmark_text(window, cx);
23977    }
23978
23979    fn replace_and_mark_text_in_range(
23980        &mut self,
23981        range_utf16: Option<Range<usize>>,
23982        text: &str,
23983        new_selected_range_utf16: Option<Range<usize>>,
23984        window: &mut Window,
23985        cx: &mut Context<Self>,
23986    ) {
23987        if !self.input_enabled {
23988            return;
23989        }
23990
23991        let transaction = self.transact(window, cx, |this, window, cx| {
23992            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23993                let snapshot = this.buffer.read(cx).read(cx);
23994                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23995                    for marked_range in &mut marked_ranges {
23996                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23997                        marked_range.start.0 += relative_range_utf16.start;
23998                        marked_range.start =
23999                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24000                        marked_range.end =
24001                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24002                    }
24003                }
24004                Some(marked_ranges)
24005            } else if let Some(range_utf16) = range_utf16 {
24006                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24007                Some(this.selection_replacement_ranges(range_utf16, cx))
24008            } else {
24009                None
24010            };
24011
24012            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24013                let newest_selection_id = this.selections.newest_anchor().id;
24014                this.selections
24015                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24016                    .iter()
24017                    .zip(ranges_to_replace.iter())
24018                    .find_map(|(selection, range)| {
24019                        if selection.id == newest_selection_id {
24020                            Some(
24021                                (range.start.0 as isize - selection.head().0 as isize)
24022                                    ..(range.end.0 as isize - selection.head().0 as isize),
24023                            )
24024                        } else {
24025                            None
24026                        }
24027                    })
24028            });
24029
24030            cx.emit(EditorEvent::InputHandled {
24031                utf16_range_to_replace: range_to_replace,
24032                text: text.into(),
24033            });
24034
24035            if let Some(ranges) = ranges_to_replace {
24036                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24037                    s.select_ranges(ranges)
24038                });
24039            }
24040
24041            let marked_ranges = {
24042                let snapshot = this.buffer.read(cx).read(cx);
24043                this.selections
24044                    .disjoint_anchors_arc()
24045                    .iter()
24046                    .map(|selection| {
24047                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24048                    })
24049                    .collect::<Vec<_>>()
24050            };
24051
24052            if text.is_empty() {
24053                this.unmark_text(window, cx);
24054            } else {
24055                this.highlight_text::<InputComposition>(
24056                    marked_ranges.clone(),
24057                    HighlightStyle {
24058                        underline: Some(UnderlineStyle {
24059                            thickness: px(1.),
24060                            color: None,
24061                            wavy: false,
24062                        }),
24063                        ..Default::default()
24064                    },
24065                    cx,
24066                );
24067            }
24068
24069            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24070            let use_autoclose = this.use_autoclose;
24071            let use_auto_surround = this.use_auto_surround;
24072            this.set_use_autoclose(false);
24073            this.set_use_auto_surround(false);
24074            this.handle_input(text, window, cx);
24075            this.set_use_autoclose(use_autoclose);
24076            this.set_use_auto_surround(use_auto_surround);
24077
24078            if let Some(new_selected_range) = new_selected_range_utf16 {
24079                let snapshot = this.buffer.read(cx).read(cx);
24080                let new_selected_ranges = marked_ranges
24081                    .into_iter()
24082                    .map(|marked_range| {
24083                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24084                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24085                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24086                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24087                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24088                    })
24089                    .collect::<Vec<_>>();
24090
24091                drop(snapshot);
24092                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24093                    selections.select_ranges(new_selected_ranges)
24094                });
24095            }
24096        });
24097
24098        self.ime_transaction = self.ime_transaction.or(transaction);
24099        if let Some(transaction) = self.ime_transaction {
24100            self.buffer.update(cx, |buffer, cx| {
24101                buffer.group_until_transaction(transaction, cx);
24102            });
24103        }
24104
24105        if self.text_highlights::<InputComposition>(cx).is_none() {
24106            self.ime_transaction.take();
24107        }
24108    }
24109
24110    fn bounds_for_range(
24111        &mut self,
24112        range_utf16: Range<usize>,
24113        element_bounds: gpui::Bounds<Pixels>,
24114        window: &mut Window,
24115        cx: &mut Context<Self>,
24116    ) -> Option<gpui::Bounds<Pixels>> {
24117        let text_layout_details = self.text_layout_details(window);
24118        let CharacterDimensions {
24119            em_width,
24120            em_advance,
24121            line_height,
24122        } = self.character_dimensions(window);
24123
24124        let snapshot = self.snapshot(window, cx);
24125        let scroll_position = snapshot.scroll_position();
24126        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24127
24128        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24129        let x = Pixels::from(
24130            ScrollOffset::from(
24131                snapshot.x_for_display_point(start, &text_layout_details)
24132                    + self.gutter_dimensions.full_width(),
24133            ) - scroll_left,
24134        );
24135        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24136
24137        Some(Bounds {
24138            origin: element_bounds.origin + point(x, y),
24139            size: size(em_width, line_height),
24140        })
24141    }
24142
24143    fn character_index_for_point(
24144        &mut self,
24145        point: gpui::Point<Pixels>,
24146        _window: &mut Window,
24147        _cx: &mut Context<Self>,
24148    ) -> Option<usize> {
24149        let position_map = self.last_position_map.as_ref()?;
24150        if !position_map.text_hitbox.contains(&point) {
24151            return None;
24152        }
24153        let display_point = position_map.point_for_position(point).previous_valid;
24154        let anchor = position_map
24155            .snapshot
24156            .display_point_to_anchor(display_point, Bias::Left);
24157        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24158        Some(utf16_offset.0)
24159    }
24160
24161    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24162        self.input_enabled
24163    }
24164}
24165
24166trait SelectionExt {
24167    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24168    fn spanned_rows(
24169        &self,
24170        include_end_if_at_line_start: bool,
24171        map: &DisplaySnapshot,
24172    ) -> Range<MultiBufferRow>;
24173}
24174
24175impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24176    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24177        let start = self
24178            .start
24179            .to_point(map.buffer_snapshot())
24180            .to_display_point(map);
24181        let end = self
24182            .end
24183            .to_point(map.buffer_snapshot())
24184            .to_display_point(map);
24185        if self.reversed {
24186            end..start
24187        } else {
24188            start..end
24189        }
24190    }
24191
24192    fn spanned_rows(
24193        &self,
24194        include_end_if_at_line_start: bool,
24195        map: &DisplaySnapshot,
24196    ) -> Range<MultiBufferRow> {
24197        let start = self.start.to_point(map.buffer_snapshot());
24198        let mut end = self.end.to_point(map.buffer_snapshot());
24199        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24200            end.row -= 1;
24201        }
24202
24203        let buffer_start = map.prev_line_boundary(start).0;
24204        let buffer_end = map.next_line_boundary(end).0;
24205        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24206    }
24207}
24208
24209impl<T: InvalidationRegion> InvalidationStack<T> {
24210    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24211    where
24212        S: Clone + ToOffset,
24213    {
24214        while let Some(region) = self.last() {
24215            let all_selections_inside_invalidation_ranges =
24216                if selections.len() == region.ranges().len() {
24217                    selections
24218                        .iter()
24219                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24220                        .all(|(selection, invalidation_range)| {
24221                            let head = selection.head().to_offset(buffer);
24222                            invalidation_range.start <= head && invalidation_range.end >= head
24223                        })
24224                } else {
24225                    false
24226                };
24227
24228            if all_selections_inside_invalidation_ranges {
24229                break;
24230            } else {
24231                self.pop();
24232            }
24233        }
24234    }
24235}
24236
24237impl<T> Default for InvalidationStack<T> {
24238    fn default() -> Self {
24239        Self(Default::default())
24240    }
24241}
24242
24243impl<T> Deref for InvalidationStack<T> {
24244    type Target = Vec<T>;
24245
24246    fn deref(&self) -> &Self::Target {
24247        &self.0
24248    }
24249}
24250
24251impl<T> DerefMut for InvalidationStack<T> {
24252    fn deref_mut(&mut self) -> &mut Self::Target {
24253        &mut self.0
24254    }
24255}
24256
24257impl InvalidationRegion for SnippetState {
24258    fn ranges(&self) -> &[Range<Anchor>] {
24259        &self.ranges[self.active_index]
24260    }
24261}
24262
24263fn edit_prediction_edit_text(
24264    current_snapshot: &BufferSnapshot,
24265    edits: &[(Range<Anchor>, String)],
24266    edit_preview: &EditPreview,
24267    include_deletions: bool,
24268    cx: &App,
24269) -> HighlightedText {
24270    let edits = edits
24271        .iter()
24272        .map(|(anchor, text)| {
24273            (
24274                anchor.start.text_anchor..anchor.end.text_anchor,
24275                text.clone(),
24276            )
24277        })
24278        .collect::<Vec<_>>();
24279
24280    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24281}
24282
24283fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24284    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24285    // Just show the raw edit text with basic styling
24286    let mut text = String::new();
24287    let mut highlights = Vec::new();
24288
24289    let insertion_highlight_style = HighlightStyle {
24290        color: Some(cx.theme().colors().text),
24291        ..Default::default()
24292    };
24293
24294    for (_, edit_text) in edits {
24295        let start_offset = text.len();
24296        text.push_str(edit_text);
24297        let end_offset = text.len();
24298
24299        if start_offset < end_offset {
24300            highlights.push((start_offset..end_offset, insertion_highlight_style));
24301        }
24302    }
24303
24304    HighlightedText {
24305        text: text.into(),
24306        highlights,
24307    }
24308}
24309
24310pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24311    match severity {
24312        lsp::DiagnosticSeverity::ERROR => colors.error,
24313        lsp::DiagnosticSeverity::WARNING => colors.warning,
24314        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24315        lsp::DiagnosticSeverity::HINT => colors.info,
24316        _ => colors.ignored,
24317    }
24318}
24319
24320pub fn styled_runs_for_code_label<'a>(
24321    label: &'a CodeLabel,
24322    syntax_theme: &'a theme::SyntaxTheme,
24323) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24324    let fade_out = HighlightStyle {
24325        fade_out: Some(0.35),
24326        ..Default::default()
24327    };
24328
24329    let mut prev_end = label.filter_range.end;
24330    label
24331        .runs
24332        .iter()
24333        .enumerate()
24334        .flat_map(move |(ix, (range, highlight_id))| {
24335            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24336                style
24337            } else {
24338                return Default::default();
24339            };
24340            let muted_style = style.highlight(fade_out);
24341
24342            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24343            if range.start >= label.filter_range.end {
24344                if range.start > prev_end {
24345                    runs.push((prev_end..range.start, fade_out));
24346                }
24347                runs.push((range.clone(), muted_style));
24348            } else if range.end <= label.filter_range.end {
24349                runs.push((range.clone(), style));
24350            } else {
24351                runs.push((range.start..label.filter_range.end, style));
24352                runs.push((label.filter_range.end..range.end, muted_style));
24353            }
24354            prev_end = cmp::max(prev_end, range.end);
24355
24356            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24357                runs.push((prev_end..label.text.len(), fade_out));
24358            }
24359
24360            runs
24361        })
24362}
24363
24364pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24365    let mut prev_index = 0;
24366    let mut prev_codepoint: Option<char> = None;
24367    text.char_indices()
24368        .chain([(text.len(), '\0')])
24369        .filter_map(move |(index, codepoint)| {
24370            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24371            let is_boundary = index == text.len()
24372                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24373                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24374            if is_boundary {
24375                let chunk = &text[prev_index..index];
24376                prev_index = index;
24377                Some(chunk)
24378            } else {
24379                None
24380            }
24381        })
24382}
24383
24384pub trait RangeToAnchorExt: Sized {
24385    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24386
24387    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24388        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24389        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24390    }
24391}
24392
24393impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24394    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24395        let start_offset = self.start.to_offset(snapshot);
24396        let end_offset = self.end.to_offset(snapshot);
24397        if start_offset == end_offset {
24398            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24399        } else {
24400            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24401        }
24402    }
24403}
24404
24405pub trait RowExt {
24406    fn as_f64(&self) -> f64;
24407
24408    fn next_row(&self) -> Self;
24409
24410    fn previous_row(&self) -> Self;
24411
24412    fn minus(&self, other: Self) -> u32;
24413}
24414
24415impl RowExt for DisplayRow {
24416    fn as_f64(&self) -> f64 {
24417        self.0 as _
24418    }
24419
24420    fn next_row(&self) -> Self {
24421        Self(self.0 + 1)
24422    }
24423
24424    fn previous_row(&self) -> Self {
24425        Self(self.0.saturating_sub(1))
24426    }
24427
24428    fn minus(&self, other: Self) -> u32 {
24429        self.0 - other.0
24430    }
24431}
24432
24433impl RowExt for MultiBufferRow {
24434    fn as_f64(&self) -> f64 {
24435        self.0 as _
24436    }
24437
24438    fn next_row(&self) -> Self {
24439        Self(self.0 + 1)
24440    }
24441
24442    fn previous_row(&self) -> Self {
24443        Self(self.0.saturating_sub(1))
24444    }
24445
24446    fn minus(&self, other: Self) -> u32 {
24447        self.0 - other.0
24448    }
24449}
24450
24451trait RowRangeExt {
24452    type Row;
24453
24454    fn len(&self) -> usize;
24455
24456    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24457}
24458
24459impl RowRangeExt for Range<MultiBufferRow> {
24460    type Row = MultiBufferRow;
24461
24462    fn len(&self) -> usize {
24463        (self.end.0 - self.start.0) as usize
24464    }
24465
24466    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24467        (self.start.0..self.end.0).map(MultiBufferRow)
24468    }
24469}
24470
24471impl RowRangeExt for Range<DisplayRow> {
24472    type Row = DisplayRow;
24473
24474    fn len(&self) -> usize {
24475        (self.end.0 - self.start.0) as usize
24476    }
24477
24478    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24479        (self.start.0..self.end.0).map(DisplayRow)
24480    }
24481}
24482
24483/// If select range has more than one line, we
24484/// just point the cursor to range.start.
24485fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24486    if range.start.row == range.end.row {
24487        range
24488    } else {
24489        range.start..range.start
24490    }
24491}
24492pub struct KillRing(ClipboardItem);
24493impl Global for KillRing {}
24494
24495const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24496
24497enum BreakpointPromptEditAction {
24498    Log,
24499    Condition,
24500    HitCondition,
24501}
24502
24503struct BreakpointPromptEditor {
24504    pub(crate) prompt: Entity<Editor>,
24505    editor: WeakEntity<Editor>,
24506    breakpoint_anchor: Anchor,
24507    breakpoint: Breakpoint,
24508    edit_action: BreakpointPromptEditAction,
24509    block_ids: HashSet<CustomBlockId>,
24510    editor_margins: Arc<Mutex<EditorMargins>>,
24511    _subscriptions: Vec<Subscription>,
24512}
24513
24514impl BreakpointPromptEditor {
24515    const MAX_LINES: u8 = 4;
24516
24517    fn new(
24518        editor: WeakEntity<Editor>,
24519        breakpoint_anchor: Anchor,
24520        breakpoint: Breakpoint,
24521        edit_action: BreakpointPromptEditAction,
24522        window: &mut Window,
24523        cx: &mut Context<Self>,
24524    ) -> Self {
24525        let base_text = match edit_action {
24526            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24527            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24528            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24529        }
24530        .map(|msg| msg.to_string())
24531        .unwrap_or_default();
24532
24533        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24534        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24535
24536        let prompt = cx.new(|cx| {
24537            let mut prompt = Editor::new(
24538                EditorMode::AutoHeight {
24539                    min_lines: 1,
24540                    max_lines: Some(Self::MAX_LINES as usize),
24541                },
24542                buffer,
24543                None,
24544                window,
24545                cx,
24546            );
24547            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24548            prompt.set_show_cursor_when_unfocused(false, cx);
24549            prompt.set_placeholder_text(
24550                match edit_action {
24551                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24552                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24553                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24554                },
24555                window,
24556                cx,
24557            );
24558
24559            prompt
24560        });
24561
24562        Self {
24563            prompt,
24564            editor,
24565            breakpoint_anchor,
24566            breakpoint,
24567            edit_action,
24568            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24569            block_ids: Default::default(),
24570            _subscriptions: vec![],
24571        }
24572    }
24573
24574    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24575        self.block_ids.extend(block_ids)
24576    }
24577
24578    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24579        if let Some(editor) = self.editor.upgrade() {
24580            let message = self
24581                .prompt
24582                .read(cx)
24583                .buffer
24584                .read(cx)
24585                .as_singleton()
24586                .expect("A multi buffer in breakpoint prompt isn't possible")
24587                .read(cx)
24588                .as_rope()
24589                .to_string();
24590
24591            editor.update(cx, |editor, cx| {
24592                editor.edit_breakpoint_at_anchor(
24593                    self.breakpoint_anchor,
24594                    self.breakpoint.clone(),
24595                    match self.edit_action {
24596                        BreakpointPromptEditAction::Log => {
24597                            BreakpointEditAction::EditLogMessage(message.into())
24598                        }
24599                        BreakpointPromptEditAction::Condition => {
24600                            BreakpointEditAction::EditCondition(message.into())
24601                        }
24602                        BreakpointPromptEditAction::HitCondition => {
24603                            BreakpointEditAction::EditHitCondition(message.into())
24604                        }
24605                    },
24606                    cx,
24607                );
24608
24609                editor.remove_blocks(self.block_ids.clone(), None, cx);
24610                cx.focus_self(window);
24611            });
24612        }
24613    }
24614
24615    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24616        self.editor
24617            .update(cx, |editor, cx| {
24618                editor.remove_blocks(self.block_ids.clone(), None, cx);
24619                window.focus(&editor.focus_handle);
24620            })
24621            .log_err();
24622    }
24623
24624    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24625        let settings = ThemeSettings::get_global(cx);
24626        let text_style = TextStyle {
24627            color: if self.prompt.read(cx).read_only(cx) {
24628                cx.theme().colors().text_disabled
24629            } else {
24630                cx.theme().colors().text
24631            },
24632            font_family: settings.buffer_font.family.clone(),
24633            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24634            font_size: settings.buffer_font_size(cx).into(),
24635            font_weight: settings.buffer_font.weight,
24636            line_height: relative(settings.buffer_line_height.value()),
24637            ..Default::default()
24638        };
24639        EditorElement::new(
24640            &self.prompt,
24641            EditorStyle {
24642                background: cx.theme().colors().editor_background,
24643                local_player: cx.theme().players().local(),
24644                text: text_style,
24645                ..Default::default()
24646            },
24647        )
24648    }
24649}
24650
24651impl Render for BreakpointPromptEditor {
24652    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24653        let editor_margins = *self.editor_margins.lock();
24654        let gutter_dimensions = editor_margins.gutter;
24655        h_flex()
24656            .key_context("Editor")
24657            .bg(cx.theme().colors().editor_background)
24658            .border_y_1()
24659            .border_color(cx.theme().status().info_border)
24660            .size_full()
24661            .py(window.line_height() / 2.5)
24662            .on_action(cx.listener(Self::confirm))
24663            .on_action(cx.listener(Self::cancel))
24664            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24665            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24666    }
24667}
24668
24669impl Focusable for BreakpointPromptEditor {
24670    fn focus_handle(&self, cx: &App) -> FocusHandle {
24671        self.prompt.focus_handle(cx)
24672    }
24673}
24674
24675fn all_edits_insertions_or_deletions(
24676    edits: &Vec<(Range<Anchor>, String)>,
24677    snapshot: &MultiBufferSnapshot,
24678) -> bool {
24679    let mut all_insertions = true;
24680    let mut all_deletions = true;
24681
24682    for (range, new_text) in edits.iter() {
24683        let range_is_empty = range.to_offset(snapshot).is_empty();
24684        let text_is_empty = new_text.is_empty();
24685
24686        if range_is_empty != text_is_empty {
24687            if range_is_empty {
24688                all_deletions = false;
24689            } else {
24690                all_insertions = false;
24691            }
24692        } else {
24693            return false;
24694        }
24695
24696        if !all_insertions && !all_deletions {
24697            return false;
24698        }
24699    }
24700    all_insertions || all_deletions
24701}
24702
24703struct MissingEditPredictionKeybindingTooltip;
24704
24705impl Render for MissingEditPredictionKeybindingTooltip {
24706    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24707        ui::tooltip_container(cx, |container, cx| {
24708            container
24709                .flex_shrink_0()
24710                .max_w_80()
24711                .min_h(rems_from_px(124.))
24712                .justify_between()
24713                .child(
24714                    v_flex()
24715                        .flex_1()
24716                        .text_ui_sm(cx)
24717                        .child(Label::new("Conflict with Accept Keybinding"))
24718                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24719                )
24720                .child(
24721                    h_flex()
24722                        .pb_1()
24723                        .gap_1()
24724                        .items_end()
24725                        .w_full()
24726                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24727                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24728                        }))
24729                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24730                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24731                        })),
24732                )
24733        })
24734    }
24735}
24736
24737#[derive(Debug, Clone, Copy, PartialEq)]
24738pub struct LineHighlight {
24739    pub background: Background,
24740    pub border: Option<gpui::Hsla>,
24741    pub include_gutter: bool,
24742    pub type_id: Option<TypeId>,
24743}
24744
24745struct LineManipulationResult {
24746    pub new_text: String,
24747    pub line_count_before: usize,
24748    pub line_count_after: usize,
24749}
24750
24751fn render_diff_hunk_controls(
24752    row: u32,
24753    status: &DiffHunkStatus,
24754    hunk_range: Range<Anchor>,
24755    is_created_file: bool,
24756    line_height: Pixels,
24757    editor: &Entity<Editor>,
24758    _win: &mut Window,
24759    cx: &mut App,
24760) -> AnyElement {
24761    h_flex()
24762        .h(line_height)
24763        .mr_1()
24764        .gap_1()
24765        .px_0p5()
24766        .pb_1()
24767        .border_x_1()
24768        .border_b_1()
24769        .border_color(cx.theme().colors().border_variant)
24770        .rounded_b_lg()
24771        .bg(cx.theme().colors().editor_background)
24772        .gap_1()
24773        .block_mouse_except_scroll()
24774        .shadow_md()
24775        .child(if status.has_secondary_hunk() {
24776            Button::new(("stage", row as u64), "Stage")
24777                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24778                .tooltip({
24779                    let focus_handle = editor.focus_handle(cx);
24780                    move |_win, cx| {
24781                        Tooltip::for_action_in(
24782                            "Stage Hunk",
24783                            &::git::ToggleStaged,
24784                            &focus_handle,
24785                            cx,
24786                        )
24787                    }
24788                })
24789                .on_click({
24790                    let editor = editor.clone();
24791                    move |_event, _window, cx| {
24792                        editor.update(cx, |editor, cx| {
24793                            editor.stage_or_unstage_diff_hunks(
24794                                true,
24795                                vec![hunk_range.start..hunk_range.start],
24796                                cx,
24797                            );
24798                        });
24799                    }
24800                })
24801        } else {
24802            Button::new(("unstage", row as u64), "Unstage")
24803                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24804                .tooltip({
24805                    let focus_handle = editor.focus_handle(cx);
24806                    move |_window, cx| {
24807                        Tooltip::for_action_in(
24808                            "Unstage Hunk",
24809                            &::git::ToggleStaged,
24810                            &focus_handle,
24811                            cx,
24812                        )
24813                    }
24814                })
24815                .on_click({
24816                    let editor = editor.clone();
24817                    move |_event, _window, cx| {
24818                        editor.update(cx, |editor, cx| {
24819                            editor.stage_or_unstage_diff_hunks(
24820                                false,
24821                                vec![hunk_range.start..hunk_range.start],
24822                                cx,
24823                            );
24824                        });
24825                    }
24826                })
24827        })
24828        .child(
24829            Button::new(("restore", row as u64), "Restore")
24830                .tooltip({
24831                    let focus_handle = editor.focus_handle(cx);
24832                    move |_window, cx| {
24833                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24834                    }
24835                })
24836                .on_click({
24837                    let editor = editor.clone();
24838                    move |_event, window, cx| {
24839                        editor.update(cx, |editor, cx| {
24840                            let snapshot = editor.snapshot(window, cx);
24841                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24842                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24843                        });
24844                    }
24845                })
24846                .disabled(is_created_file),
24847        )
24848        .when(
24849            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24850            |el| {
24851                el.child(
24852                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24853                        .shape(IconButtonShape::Square)
24854                        .icon_size(IconSize::Small)
24855                        // .disabled(!has_multiple_hunks)
24856                        .tooltip({
24857                            let focus_handle = editor.focus_handle(cx);
24858                            move |_window, cx| {
24859                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24860                            }
24861                        })
24862                        .on_click({
24863                            let editor = editor.clone();
24864                            move |_event, window, cx| {
24865                                editor.update(cx, |editor, cx| {
24866                                    let snapshot = editor.snapshot(window, cx);
24867                                    let position =
24868                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24869                                    editor.go_to_hunk_before_or_after_position(
24870                                        &snapshot,
24871                                        position,
24872                                        Direction::Next,
24873                                        window,
24874                                        cx,
24875                                    );
24876                                    editor.expand_selected_diff_hunks(cx);
24877                                });
24878                            }
24879                        }),
24880                )
24881                .child(
24882                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24883                        .shape(IconButtonShape::Square)
24884                        .icon_size(IconSize::Small)
24885                        // .disabled(!has_multiple_hunks)
24886                        .tooltip({
24887                            let focus_handle = editor.focus_handle(cx);
24888                            move |_window, cx| {
24889                                Tooltip::for_action_in(
24890                                    "Previous Hunk",
24891                                    &GoToPreviousHunk,
24892                                    &focus_handle,
24893                                    cx,
24894                                )
24895                            }
24896                        })
24897                        .on_click({
24898                            let editor = editor.clone();
24899                            move |_event, window, cx| {
24900                                editor.update(cx, |editor, cx| {
24901                                    let snapshot = editor.snapshot(window, cx);
24902                                    let point =
24903                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24904                                    editor.go_to_hunk_before_or_after_position(
24905                                        &snapshot,
24906                                        point,
24907                                        Direction::Prev,
24908                                        window,
24909                                        cx,
24910                                    );
24911                                    editor.expand_selected_diff_hunks(cx);
24912                                });
24913                            }
24914                        }),
24915                )
24916            },
24917        )
24918        .into_any_element()
24919}
24920
24921pub fn multibuffer_context_lines(cx: &App) -> u32 {
24922    EditorSettings::try_get(cx)
24923        .map(|settings| settings.excerpt_context_lines)
24924        .unwrap_or(2)
24925        .min(32)
24926}