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, AhoCorasickBuilder, BuildError};
   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, OutlineItem, Point, Runnable, RunnableRange, Selection,
  121    SelectionGoal, 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(cx: &mut App) {
  314    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  315
  316    workspace::register_project_item::<Editor>(cx);
  317    workspace::FollowableViewRegistry::register::<Editor>(cx);
  318    workspace::register_serializable_item::<Editor>(cx);
  319
  320    cx.observe_new(
  321        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  322            workspace.register_action(Editor::new_file);
  323            workspace.register_action(Editor::new_file_split);
  324            workspace.register_action(Editor::new_file_vertical);
  325            workspace.register_action(Editor::new_file_horizontal);
  326            workspace.register_action(Editor::cancel_language_server_work);
  327            workspace.register_action(Editor::toggle_focus);
  328        },
  329    )
  330    .detach();
  331
  332    cx.on_action(move |_: &workspace::NewFile, cx| {
  333        let app_state = workspace::AppState::global(cx);
  334        if let Some(app_state) = app_state.upgrade() {
  335            workspace::open_new(
  336                Default::default(),
  337                app_state,
  338                cx,
  339                |workspace, window, cx| {
  340                    Editor::new_file(workspace, &Default::default(), window, cx)
  341                },
  342            )
  343            .detach();
  344        }
  345    });
  346    cx.on_action(move |_: &workspace::NewWindow, cx| {
  347        let app_state = workspace::AppState::global(cx);
  348        if let Some(app_state) = app_state.upgrade() {
  349            workspace::open_new(
  350                Default::default(),
  351                app_state,
  352                cx,
  353                |workspace, window, cx| {
  354                    cx.activate(true);
  355                    Editor::new_file(workspace, &Default::default(), window, cx)
  356                },
  357            )
  358            .detach();
  359        }
  360    });
  361}
  362
  363pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  364    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  365}
  366
  367pub trait DiagnosticRenderer {
  368    fn render_group(
  369        &self,
  370        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  371        buffer_id: BufferId,
  372        snapshot: EditorSnapshot,
  373        editor: WeakEntity<Editor>,
  374        cx: &mut App,
  375    ) -> Vec<BlockProperties<Anchor>>;
  376
  377    fn render_hover(
  378        &self,
  379        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  380        range: Range<Point>,
  381        buffer_id: BufferId,
  382        cx: &mut App,
  383    ) -> Option<Entity<markdown::Markdown>>;
  384
  385    fn open_link(
  386        &self,
  387        editor: &mut Editor,
  388        link: SharedString,
  389        window: &mut Window,
  390        cx: &mut Context<Editor>,
  391    );
  392}
  393
  394pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  395
  396impl GlobalDiagnosticRenderer {
  397    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  398        cx.try_global::<Self>().map(|g| g.0.clone())
  399    }
  400}
  401
  402impl gpui::Global for GlobalDiagnosticRenderer {}
  403pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  404    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  405}
  406
  407pub struct SearchWithinRange;
  408
  409trait InvalidationRegion {
  410    fn ranges(&self) -> &[Range<Anchor>];
  411}
  412
  413#[derive(Clone, Debug, PartialEq)]
  414pub enum SelectPhase {
  415    Begin {
  416        position: DisplayPoint,
  417        add: bool,
  418        click_count: usize,
  419    },
  420    BeginColumnar {
  421        position: DisplayPoint,
  422        reset: bool,
  423        mode: ColumnarMode,
  424        goal_column: u32,
  425    },
  426    Extend {
  427        position: DisplayPoint,
  428        click_count: usize,
  429    },
  430    Update {
  431        position: DisplayPoint,
  432        goal_column: u32,
  433        scroll_delta: gpui::Point<f32>,
  434    },
  435    End,
  436}
  437
  438#[derive(Clone, Debug, PartialEq)]
  439pub enum ColumnarMode {
  440    FromMouse,
  441    FromSelection,
  442}
  443
  444#[derive(Clone, Debug)]
  445pub enum SelectMode {
  446    Character,
  447    Word(Range<Anchor>),
  448    Line(Range<Anchor>),
  449    All,
  450}
  451
  452#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  453pub enum SizingBehavior {
  454    /// The editor will layout itself using `size_full` and will include the vertical
  455    /// scroll margin as requested by user settings.
  456    #[default]
  457    Default,
  458    /// The editor will layout itself using `size_full`, but will not have any
  459    /// vertical overscroll.
  460    ExcludeOverscrollMargin,
  461    /// The editor will request a vertical size according to its content and will be
  462    /// layouted without a vertical scroll margin.
  463    SizeByContent,
  464}
  465
  466#[derive(Clone, PartialEq, Eq, Debug)]
  467pub enum EditorMode {
  468    SingleLine,
  469    AutoHeight {
  470        min_lines: usize,
  471        max_lines: Option<usize>,
  472    },
  473    Full {
  474        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  475        scale_ui_elements_with_buffer_font_size: bool,
  476        /// When set to `true`, the editor will render a background for the active line.
  477        show_active_line_background: bool,
  478        /// Determines the sizing behavior for this editor
  479        sizing_behavior: SizingBehavior,
  480    },
  481    Minimap {
  482        parent: WeakEntity<Editor>,
  483    },
  484}
  485
  486impl EditorMode {
  487    pub fn full() -> Self {
  488        Self::Full {
  489            scale_ui_elements_with_buffer_font_size: true,
  490            show_active_line_background: true,
  491            sizing_behavior: SizingBehavior::Default,
  492        }
  493    }
  494
  495    #[inline]
  496    pub fn is_full(&self) -> bool {
  497        matches!(self, Self::Full { .. })
  498    }
  499
  500    #[inline]
  501    pub fn is_single_line(&self) -> bool {
  502        matches!(self, Self::SingleLine { .. })
  503    }
  504
  505    #[inline]
  506    fn is_minimap(&self) -> bool {
  507        matches!(self, Self::Minimap { .. })
  508    }
  509}
  510
  511#[derive(Copy, Clone, Debug)]
  512pub enum SoftWrap {
  513    /// Prefer not to wrap at all.
  514    ///
  515    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  516    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  517    GitDiff,
  518    /// Prefer a single line generally, unless an overly long line is encountered.
  519    None,
  520    /// Soft wrap lines that exceed the editor width.
  521    EditorWidth,
  522    /// Soft wrap lines at the preferred line length.
  523    Column(u32),
  524    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  525    Bounded(u32),
  526}
  527
  528#[derive(Clone)]
  529pub struct EditorStyle {
  530    pub background: Hsla,
  531    pub border: Hsla,
  532    pub local_player: PlayerColor,
  533    pub text: TextStyle,
  534    pub scrollbar_width: Pixels,
  535    pub syntax: Arc<SyntaxTheme>,
  536    pub status: StatusColors,
  537    pub inlay_hints_style: HighlightStyle,
  538    pub edit_prediction_styles: EditPredictionStyles,
  539    pub unnecessary_code_fade: f32,
  540    pub show_underlines: bool,
  541}
  542
  543impl Default for EditorStyle {
  544    fn default() -> Self {
  545        Self {
  546            background: Hsla::default(),
  547            border: Hsla::default(),
  548            local_player: PlayerColor::default(),
  549            text: TextStyle::default(),
  550            scrollbar_width: Pixels::default(),
  551            syntax: Default::default(),
  552            // HACK: Status colors don't have a real default.
  553            // We should look into removing the status colors from the editor
  554            // style and retrieve them directly from the theme.
  555            status: StatusColors::dark(),
  556            inlay_hints_style: HighlightStyle::default(),
  557            edit_prediction_styles: EditPredictionStyles {
  558                insertion: HighlightStyle::default(),
  559                whitespace: HighlightStyle::default(),
  560            },
  561            unnecessary_code_fade: Default::default(),
  562            show_underlines: true,
  563        }
  564    }
  565}
  566
  567pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  568    let show_background = language_settings::language_settings(None, None, cx)
  569        .inlay_hints
  570        .show_background;
  571
  572    let mut style = cx.theme().syntax().get("hint");
  573
  574    if style.color.is_none() {
  575        style.color = Some(cx.theme().status().hint);
  576    }
  577
  578    if !show_background {
  579        style.background_color = None;
  580        return style;
  581    }
  582
  583    if style.background_color.is_none() {
  584        style.background_color = Some(cx.theme().status().hint_background);
  585    }
  586
  587    style
  588}
  589
  590pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  591    EditPredictionStyles {
  592        insertion: HighlightStyle {
  593            color: Some(cx.theme().status().predictive),
  594            ..HighlightStyle::default()
  595        },
  596        whitespace: HighlightStyle {
  597            background_color: Some(cx.theme().status().created_background),
  598            ..HighlightStyle::default()
  599        },
  600    }
  601}
  602
  603type CompletionId = usize;
  604
  605pub(crate) enum EditDisplayMode {
  606    TabAccept,
  607    DiffPopover,
  608    Inline,
  609}
  610
  611enum EditPrediction {
  612    Edit {
  613        edits: Vec<(Range<Anchor>, Arc<str>)>,
  614        edit_preview: Option<EditPreview>,
  615        display_mode: EditDisplayMode,
  616        snapshot: BufferSnapshot,
  617    },
  618    /// Move to a specific location in the active editor
  619    MoveWithin {
  620        target: Anchor,
  621        snapshot: BufferSnapshot,
  622    },
  623    /// Move to a specific location in a different editor (not the active one)
  624    MoveOutside {
  625        target: language::Anchor,
  626        snapshot: BufferSnapshot,
  627    },
  628}
  629
  630struct EditPredictionState {
  631    inlay_ids: Vec<InlayId>,
  632    completion: EditPrediction,
  633    completion_id: Option<SharedString>,
  634    invalidation_range: Option<Range<Anchor>>,
  635}
  636
  637enum EditPredictionSettings {
  638    Disabled,
  639    Enabled {
  640        show_in_menu: bool,
  641        preview_requires_modifier: bool,
  642    },
  643}
  644
  645enum EditPredictionHighlight {}
  646
  647#[derive(Debug, Clone)]
  648struct InlineDiagnostic {
  649    message: SharedString,
  650    group_id: usize,
  651    is_primary: bool,
  652    start: Point,
  653    severity: lsp::DiagnosticSeverity,
  654}
  655
  656pub enum MenuEditPredictionsPolicy {
  657    Never,
  658    ByProvider,
  659}
  660
  661pub enum EditPredictionPreview {
  662    /// Modifier is not pressed
  663    Inactive { released_too_fast: bool },
  664    /// Modifier pressed
  665    Active {
  666        since: Instant,
  667        previous_scroll_position: Option<ScrollAnchor>,
  668    },
  669}
  670
  671impl EditPredictionPreview {
  672    pub fn released_too_fast(&self) -> bool {
  673        match self {
  674            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  675            EditPredictionPreview::Active { .. } => false,
  676        }
  677    }
  678
  679    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  680        if let EditPredictionPreview::Active {
  681            previous_scroll_position,
  682            ..
  683        } = self
  684        {
  685            *previous_scroll_position = scroll_position;
  686        }
  687    }
  688}
  689
  690pub struct ContextMenuOptions {
  691    pub min_entries_visible: usize,
  692    pub max_entries_visible: usize,
  693    pub placement: Option<ContextMenuPlacement>,
  694}
  695
  696#[derive(Debug, Clone, PartialEq, Eq)]
  697pub enum ContextMenuPlacement {
  698    Above,
  699    Below,
  700}
  701
  702#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  703struct EditorActionId(usize);
  704
  705impl EditorActionId {
  706    pub fn post_inc(&mut self) -> Self {
  707        let answer = self.0;
  708
  709        *self = Self(answer + 1);
  710
  711        Self(answer)
  712    }
  713}
  714
  715// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  716// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  717
  718type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  719type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  720
  721#[derive(Default)]
  722struct ScrollbarMarkerState {
  723    scrollbar_size: Size<Pixels>,
  724    dirty: bool,
  725    markers: Arc<[PaintQuad]>,
  726    pending_refresh: Option<Task<Result<()>>>,
  727}
  728
  729impl ScrollbarMarkerState {
  730    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  731        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  732    }
  733}
  734
  735#[derive(Clone, Copy, PartialEq, Eq)]
  736pub enum MinimapVisibility {
  737    Disabled,
  738    Enabled {
  739        /// The configuration currently present in the users settings.
  740        setting_configuration: bool,
  741        /// Whether to override the currently set visibility from the users setting.
  742        toggle_override: bool,
  743    },
  744}
  745
  746impl MinimapVisibility {
  747    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  748        if mode.is_full() {
  749            Self::Enabled {
  750                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  751                toggle_override: false,
  752            }
  753        } else {
  754            Self::Disabled
  755        }
  756    }
  757
  758    fn hidden(&self) -> Self {
  759        match *self {
  760            Self::Enabled {
  761                setting_configuration,
  762                ..
  763            } => Self::Enabled {
  764                setting_configuration,
  765                toggle_override: setting_configuration,
  766            },
  767            Self::Disabled => Self::Disabled,
  768        }
  769    }
  770
  771    fn disabled(&self) -> bool {
  772        matches!(*self, Self::Disabled)
  773    }
  774
  775    fn settings_visibility(&self) -> bool {
  776        match *self {
  777            Self::Enabled {
  778                setting_configuration,
  779                ..
  780            } => setting_configuration,
  781            _ => false,
  782        }
  783    }
  784
  785    fn visible(&self) -> bool {
  786        match *self {
  787            Self::Enabled {
  788                setting_configuration,
  789                toggle_override,
  790            } => setting_configuration ^ toggle_override,
  791            _ => false,
  792        }
  793    }
  794
  795    fn toggle_visibility(&self) -> Self {
  796        match *self {
  797            Self::Enabled {
  798                toggle_override,
  799                setting_configuration,
  800            } => Self::Enabled {
  801                setting_configuration,
  802                toggle_override: !toggle_override,
  803            },
  804            Self::Disabled => Self::Disabled,
  805        }
  806    }
  807}
  808
  809#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  810pub enum BufferSerialization {
  811    All,
  812    NonDirtyBuffers,
  813}
  814
  815impl BufferSerialization {
  816    fn new(restore_unsaved_buffers: bool) -> Self {
  817        if restore_unsaved_buffers {
  818            Self::All
  819        } else {
  820            Self::NonDirtyBuffers
  821        }
  822    }
  823}
  824
  825#[derive(Clone, Debug)]
  826struct RunnableTasks {
  827    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  828    offset: multi_buffer::Anchor,
  829    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  830    column: u32,
  831    // Values of all named captures, including those starting with '_'
  832    extra_variables: HashMap<String, String>,
  833    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  834    context_range: Range<BufferOffset>,
  835}
  836
  837impl RunnableTasks {
  838    fn resolve<'a>(
  839        &'a self,
  840        cx: &'a task::TaskContext,
  841    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  842        self.templates.iter().filter_map(|(kind, template)| {
  843            template
  844                .resolve_task(&kind.to_id_base(), cx)
  845                .map(|task| (kind.clone(), task))
  846        })
  847    }
  848}
  849
  850#[derive(Clone)]
  851pub struct ResolvedTasks {
  852    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  853    position: Anchor,
  854}
  855
  856#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  857struct BufferOffset(usize);
  858
  859/// Addons allow storing per-editor state in other crates (e.g. Vim)
  860pub trait Addon: 'static {
  861    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  862
  863    fn render_buffer_header_controls(
  864        &self,
  865        _: &ExcerptInfo,
  866        _: &Window,
  867        _: &App,
  868    ) -> Option<AnyElement> {
  869        None
  870    }
  871
  872    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  873        None
  874    }
  875
  876    fn to_any(&self) -> &dyn std::any::Any;
  877
  878    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  879        None
  880    }
  881}
  882
  883struct ChangeLocation {
  884    current: Option<Vec<Anchor>>,
  885    original: Vec<Anchor>,
  886}
  887impl ChangeLocation {
  888    fn locations(&self) -> &[Anchor] {
  889        self.current.as_ref().unwrap_or(&self.original)
  890    }
  891}
  892
  893/// A set of caret positions, registered when the editor was edited.
  894pub struct ChangeList {
  895    changes: Vec<ChangeLocation>,
  896    /// Currently "selected" change.
  897    position: Option<usize>,
  898}
  899
  900impl ChangeList {
  901    pub fn new() -> Self {
  902        Self {
  903            changes: Vec::new(),
  904            position: None,
  905        }
  906    }
  907
  908    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  909    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  910    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  911        if self.changes.is_empty() {
  912            return None;
  913        }
  914
  915        let prev = self.position.unwrap_or(self.changes.len());
  916        let next = if direction == Direction::Prev {
  917            prev.saturating_sub(count)
  918        } else {
  919            (prev + count).min(self.changes.len() - 1)
  920        };
  921        self.position = Some(next);
  922        self.changes.get(next).map(|change| change.locations())
  923    }
  924
  925    /// Adds a new change to the list, resetting the change list position.
  926    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  927        self.position.take();
  928        if let Some(last) = self.changes.last_mut()
  929            && group
  930        {
  931            last.current = Some(new_positions)
  932        } else {
  933            self.changes.push(ChangeLocation {
  934                original: new_positions,
  935                current: None,
  936            });
  937        }
  938    }
  939
  940    pub fn last(&self) -> Option<&[Anchor]> {
  941        self.changes.last().map(|change| change.locations())
  942    }
  943
  944    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  945        self.changes.last().map(|change| change.original.as_slice())
  946    }
  947
  948    pub fn invert_last_group(&mut self) {
  949        if let Some(last) = self.changes.last_mut()
  950            && let Some(current) = last.current.as_mut()
  951        {
  952            mem::swap(&mut last.original, current);
  953        }
  954    }
  955}
  956
  957#[derive(Clone)]
  958struct InlineBlamePopoverState {
  959    scroll_handle: ScrollHandle,
  960    commit_message: Option<ParsedCommitMessage>,
  961    markdown: Entity<Markdown>,
  962}
  963
  964struct InlineBlamePopover {
  965    position: gpui::Point<Pixels>,
  966    hide_task: Option<Task<()>>,
  967    popover_bounds: Option<Bounds<Pixels>>,
  968    popover_state: InlineBlamePopoverState,
  969    keyboard_grace: bool,
  970}
  971
  972enum SelectionDragState {
  973    /// State when no drag related activity is detected.
  974    None,
  975    /// State when the mouse is down on a selection that is about to be dragged.
  976    ReadyToDrag {
  977        selection: Selection<Anchor>,
  978        click_position: gpui::Point<Pixels>,
  979        mouse_down_time: Instant,
  980    },
  981    /// State when the mouse is dragging the selection in the editor.
  982    Dragging {
  983        selection: Selection<Anchor>,
  984        drop_cursor: Selection<Anchor>,
  985        hide_drop_cursor: bool,
  986    },
  987}
  988
  989enum ColumnarSelectionState {
  990    FromMouse {
  991        selection_tail: Anchor,
  992        display_point: Option<DisplayPoint>,
  993    },
  994    FromSelection {
  995        selection_tail: Anchor,
  996    },
  997}
  998
  999/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1000/// a breakpoint on them.
 1001#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1002struct PhantomBreakpointIndicator {
 1003    display_row: DisplayRow,
 1004    /// There's a small debounce between hovering over the line and showing the indicator.
 1005    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1006    is_active: bool,
 1007    collides_with_existing_breakpoint: bool,
 1008}
 1009
 1010/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1011///
 1012/// See the [module level documentation](self) for more information.
 1013pub struct Editor {
 1014    focus_handle: FocusHandle,
 1015    last_focused_descendant: Option<WeakFocusHandle>,
 1016    /// The text buffer being edited
 1017    buffer: Entity<MultiBuffer>,
 1018    /// Map of how text in the buffer should be displayed.
 1019    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1020    pub display_map: Entity<DisplayMap>,
 1021    placeholder_display_map: Option<Entity<DisplayMap>>,
 1022    pub selections: SelectionsCollection,
 1023    pub scroll_manager: ScrollManager,
 1024    /// When inline assist editors are linked, they all render cursors because
 1025    /// typing enters text into each of them, even the ones that aren't focused.
 1026    pub(crate) show_cursor_when_unfocused: bool,
 1027    columnar_selection_state: Option<ColumnarSelectionState>,
 1028    add_selections_state: Option<AddSelectionsState>,
 1029    select_next_state: Option<SelectNextState>,
 1030    select_prev_state: Option<SelectNextState>,
 1031    selection_history: SelectionHistory,
 1032    defer_selection_effects: bool,
 1033    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1034    autoclose_regions: Vec<AutocloseRegion>,
 1035    snippet_stack: InvalidationStack<SnippetState>,
 1036    select_syntax_node_history: SelectSyntaxNodeHistory,
 1037    ime_transaction: Option<TransactionId>,
 1038    pub diagnostics_max_severity: DiagnosticSeverity,
 1039    active_diagnostics: ActiveDiagnostic,
 1040    show_inline_diagnostics: bool,
 1041    inline_diagnostics_update: Task<()>,
 1042    inline_diagnostics_enabled: bool,
 1043    diagnostics_enabled: bool,
 1044    word_completions_enabled: bool,
 1045    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1046    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1047    hard_wrap: Option<usize>,
 1048    project: Option<Entity<Project>>,
 1049    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1050    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1051    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1052    blink_manager: Entity<BlinkManager>,
 1053    show_cursor_names: bool,
 1054    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1055    pub show_local_selections: bool,
 1056    mode: EditorMode,
 1057    show_breadcrumbs: bool,
 1058    show_gutter: bool,
 1059    show_scrollbars: ScrollbarAxes,
 1060    minimap_visibility: MinimapVisibility,
 1061    offset_content: bool,
 1062    disable_expand_excerpt_buttons: bool,
 1063    show_line_numbers: Option<bool>,
 1064    use_relative_line_numbers: Option<bool>,
 1065    show_git_diff_gutter: Option<bool>,
 1066    show_code_actions: Option<bool>,
 1067    show_runnables: Option<bool>,
 1068    show_breakpoints: Option<bool>,
 1069    show_wrap_guides: Option<bool>,
 1070    show_indent_guides: Option<bool>,
 1071    highlight_order: usize,
 1072    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1073    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1074    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1075    scrollbar_marker_state: ScrollbarMarkerState,
 1076    active_indent_guides_state: ActiveIndentGuidesState,
 1077    nav_history: Option<ItemNavHistory>,
 1078    context_menu: RefCell<Option<CodeContextMenu>>,
 1079    context_menu_options: Option<ContextMenuOptions>,
 1080    mouse_context_menu: Option<MouseContextMenu>,
 1081    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1082    inline_blame_popover: Option<InlineBlamePopover>,
 1083    inline_blame_popover_show_task: Option<Task<()>>,
 1084    signature_help_state: SignatureHelpState,
 1085    auto_signature_help: Option<bool>,
 1086    find_all_references_task_sources: Vec<Anchor>,
 1087    next_completion_id: CompletionId,
 1088    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1089    code_actions_task: Option<Task<Result<()>>>,
 1090    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1091    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1092    document_highlights_task: Option<Task<()>>,
 1093    linked_editing_range_task: Option<Task<Option<()>>>,
 1094    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1095    pending_rename: Option<RenameState>,
 1096    searchable: bool,
 1097    cursor_shape: CursorShape,
 1098    current_line_highlight: Option<CurrentLineHighlight>,
 1099    autoindent_mode: Option<AutoindentMode>,
 1100    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1101    input_enabled: bool,
 1102    use_modal_editing: bool,
 1103    read_only: bool,
 1104    leader_id: Option<CollaboratorId>,
 1105    remote_id: Option<ViewId>,
 1106    pub hover_state: HoverState,
 1107    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1108    gutter_hovered: bool,
 1109    hovered_link_state: Option<HoveredLinkState>,
 1110    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1111    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1112    active_edit_prediction: Option<EditPredictionState>,
 1113    /// Used to prevent flickering as the user types while the menu is open
 1114    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1115    edit_prediction_settings: EditPredictionSettings,
 1116    edit_predictions_hidden_for_vim_mode: bool,
 1117    show_edit_predictions_override: Option<bool>,
 1118    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1119    edit_prediction_preview: EditPredictionPreview,
 1120    edit_prediction_indent_conflict: bool,
 1121    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1122    next_inlay_id: usize,
 1123    next_color_inlay_id: usize,
 1124    _subscriptions: Vec<Subscription>,
 1125    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1126    gutter_dimensions: GutterDimensions,
 1127    style: Option<EditorStyle>,
 1128    text_style_refinement: Option<TextStyleRefinement>,
 1129    next_editor_action_id: EditorActionId,
 1130    editor_actions: Rc<
 1131        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1132    >,
 1133    use_autoclose: bool,
 1134    use_auto_surround: bool,
 1135    auto_replace_emoji_shortcode: bool,
 1136    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1137    show_git_blame_gutter: bool,
 1138    show_git_blame_inline: bool,
 1139    show_git_blame_inline_delay_task: Option<Task<()>>,
 1140    git_blame_inline_enabled: bool,
 1141    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1142    buffer_serialization: Option<BufferSerialization>,
 1143    show_selection_menu: Option<bool>,
 1144    blame: Option<Entity<GitBlame>>,
 1145    blame_subscription: Option<Subscription>,
 1146    custom_context_menu: Option<
 1147        Box<
 1148            dyn 'static
 1149                + Fn(
 1150                    &mut Self,
 1151                    DisplayPoint,
 1152                    &mut Window,
 1153                    &mut Context<Self>,
 1154                ) -> Option<Entity<ui::ContextMenu>>,
 1155        >,
 1156    >,
 1157    last_bounds: Option<Bounds<Pixels>>,
 1158    last_position_map: Option<Rc<PositionMap>>,
 1159    expect_bounds_change: Option<Bounds<Pixels>>,
 1160    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1161    tasks_update_task: Option<Task<()>>,
 1162    breakpoint_store: Option<Entity<BreakpointStore>>,
 1163    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1164    hovered_diff_hunk_row: Option<DisplayRow>,
 1165    pull_diagnostics_task: Task<()>,
 1166    in_project_search: bool,
 1167    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1168    breadcrumb_header: Option<String>,
 1169    focused_block: Option<FocusedBlock>,
 1170    next_scroll_position: NextScrollCursorCenterTopBottom,
 1171    addons: HashMap<TypeId, Box<dyn Addon>>,
 1172    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1173    load_diff_task: Option<Shared<Task<()>>>,
 1174    /// Whether we are temporarily displaying a diff other than git's
 1175    temporary_diff_override: bool,
 1176    selection_mark_mode: bool,
 1177    toggle_fold_multiple_buffers: Task<()>,
 1178    _scroll_cursor_center_top_bottom_task: Task<()>,
 1179    serialize_selections: Task<()>,
 1180    serialize_folds: Task<()>,
 1181    mouse_cursor_hidden: bool,
 1182    minimap: Option<Entity<Self>>,
 1183    hide_mouse_mode: HideMouseMode,
 1184    pub change_list: ChangeList,
 1185    inline_value_cache: InlineValueCache,
 1186
 1187    selection_drag_state: SelectionDragState,
 1188    colors: Option<LspColorData>,
 1189    post_scroll_update: Task<()>,
 1190    refresh_colors_task: Task<()>,
 1191    inlay_hints: Option<LspInlayHintData>,
 1192    folding_newlines: Task<()>,
 1193    select_next_is_case_sensitive: Option<bool>,
 1194    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1195}
 1196
 1197fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1198    if debounce_ms > 0 {
 1199        Some(Duration::from_millis(debounce_ms))
 1200    } else {
 1201        None
 1202    }
 1203}
 1204
 1205#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1206enum NextScrollCursorCenterTopBottom {
 1207    #[default]
 1208    Center,
 1209    Top,
 1210    Bottom,
 1211}
 1212
 1213impl NextScrollCursorCenterTopBottom {
 1214    fn next(&self) -> Self {
 1215        match self {
 1216            Self::Center => Self::Top,
 1217            Self::Top => Self::Bottom,
 1218            Self::Bottom => Self::Center,
 1219        }
 1220    }
 1221}
 1222
 1223#[derive(Clone)]
 1224pub struct EditorSnapshot {
 1225    pub mode: EditorMode,
 1226    show_gutter: bool,
 1227    show_line_numbers: Option<bool>,
 1228    show_git_diff_gutter: Option<bool>,
 1229    show_code_actions: Option<bool>,
 1230    show_runnables: Option<bool>,
 1231    show_breakpoints: Option<bool>,
 1232    git_blame_gutter_max_author_length: Option<usize>,
 1233    pub display_snapshot: DisplaySnapshot,
 1234    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1235    is_focused: bool,
 1236    scroll_anchor: ScrollAnchor,
 1237    ongoing_scroll: OngoingScroll,
 1238    current_line_highlight: CurrentLineHighlight,
 1239    gutter_hovered: bool,
 1240}
 1241
 1242#[derive(Default, Debug, Clone, Copy)]
 1243pub struct GutterDimensions {
 1244    pub left_padding: Pixels,
 1245    pub right_padding: Pixels,
 1246    pub width: Pixels,
 1247    pub margin: Pixels,
 1248    pub git_blame_entries_width: Option<Pixels>,
 1249}
 1250
 1251impl GutterDimensions {
 1252    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1253        Self {
 1254            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1255            ..Default::default()
 1256        }
 1257    }
 1258
 1259    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1260        -cx.text_system().descent(font_id, font_size)
 1261    }
 1262    /// The full width of the space taken up by the gutter.
 1263    pub fn full_width(&self) -> Pixels {
 1264        self.margin + self.width
 1265    }
 1266
 1267    /// The width of the space reserved for the fold indicators,
 1268    /// use alongside 'justify_end' and `gutter_width` to
 1269    /// right align content with the line numbers
 1270    pub fn fold_area_width(&self) -> Pixels {
 1271        self.margin + self.right_padding
 1272    }
 1273}
 1274
 1275struct CharacterDimensions {
 1276    em_width: Pixels,
 1277    em_advance: Pixels,
 1278    line_height: Pixels,
 1279}
 1280
 1281#[derive(Debug)]
 1282pub struct RemoteSelection {
 1283    pub replica_id: ReplicaId,
 1284    pub selection: Selection<Anchor>,
 1285    pub cursor_shape: CursorShape,
 1286    pub collaborator_id: CollaboratorId,
 1287    pub line_mode: bool,
 1288    pub user_name: Option<SharedString>,
 1289    pub color: PlayerColor,
 1290}
 1291
 1292#[derive(Clone, Debug)]
 1293struct SelectionHistoryEntry {
 1294    selections: Arc<[Selection<Anchor>]>,
 1295    select_next_state: Option<SelectNextState>,
 1296    select_prev_state: Option<SelectNextState>,
 1297    add_selections_state: Option<AddSelectionsState>,
 1298}
 1299
 1300#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1301enum SelectionHistoryMode {
 1302    Normal,
 1303    Undoing,
 1304    Redoing,
 1305    Skipping,
 1306}
 1307
 1308#[derive(Clone, PartialEq, Eq, Hash)]
 1309struct HoveredCursor {
 1310    replica_id: ReplicaId,
 1311    selection_id: usize,
 1312}
 1313
 1314impl Default for SelectionHistoryMode {
 1315    fn default() -> Self {
 1316        Self::Normal
 1317    }
 1318}
 1319
 1320#[derive(Debug)]
 1321/// SelectionEffects controls the side-effects of updating the selection.
 1322///
 1323/// The default behaviour does "what you mostly want":
 1324/// - it pushes to the nav history if the cursor moved by >10 lines
 1325/// - it re-triggers completion requests
 1326/// - it scrolls to fit
 1327///
 1328/// You might want to modify these behaviours. For example when doing a "jump"
 1329/// like go to definition, we always want to add to nav history; but when scrolling
 1330/// in vim mode we never do.
 1331///
 1332/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1333/// move.
 1334#[derive(Clone)]
 1335pub struct SelectionEffects {
 1336    nav_history: Option<bool>,
 1337    completions: bool,
 1338    scroll: Option<Autoscroll>,
 1339}
 1340
 1341impl Default for SelectionEffects {
 1342    fn default() -> Self {
 1343        Self {
 1344            nav_history: None,
 1345            completions: true,
 1346            scroll: Some(Autoscroll::fit()),
 1347        }
 1348    }
 1349}
 1350impl SelectionEffects {
 1351    pub fn scroll(scroll: Autoscroll) -> Self {
 1352        Self {
 1353            scroll: Some(scroll),
 1354            ..Default::default()
 1355        }
 1356    }
 1357
 1358    pub fn no_scroll() -> Self {
 1359        Self {
 1360            scroll: None,
 1361            ..Default::default()
 1362        }
 1363    }
 1364
 1365    pub fn completions(self, completions: bool) -> Self {
 1366        Self {
 1367            completions,
 1368            ..self
 1369        }
 1370    }
 1371
 1372    pub fn nav_history(self, nav_history: bool) -> Self {
 1373        Self {
 1374            nav_history: Some(nav_history),
 1375            ..self
 1376        }
 1377    }
 1378}
 1379
 1380struct DeferredSelectionEffectsState {
 1381    changed: bool,
 1382    effects: SelectionEffects,
 1383    old_cursor_position: Anchor,
 1384    history_entry: SelectionHistoryEntry,
 1385}
 1386
 1387#[derive(Default)]
 1388struct SelectionHistory {
 1389    #[allow(clippy::type_complexity)]
 1390    selections_by_transaction:
 1391        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1392    mode: SelectionHistoryMode,
 1393    undo_stack: VecDeque<SelectionHistoryEntry>,
 1394    redo_stack: VecDeque<SelectionHistoryEntry>,
 1395}
 1396
 1397impl SelectionHistory {
 1398    #[track_caller]
 1399    fn insert_transaction(
 1400        &mut self,
 1401        transaction_id: TransactionId,
 1402        selections: Arc<[Selection<Anchor>]>,
 1403    ) {
 1404        if selections.is_empty() {
 1405            log::error!(
 1406                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1407                std::panic::Location::caller()
 1408            );
 1409            return;
 1410        }
 1411        self.selections_by_transaction
 1412            .insert(transaction_id, (selections, None));
 1413    }
 1414
 1415    #[allow(clippy::type_complexity)]
 1416    fn transaction(
 1417        &self,
 1418        transaction_id: TransactionId,
 1419    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1420        self.selections_by_transaction.get(&transaction_id)
 1421    }
 1422
 1423    #[allow(clippy::type_complexity)]
 1424    fn transaction_mut(
 1425        &mut self,
 1426        transaction_id: TransactionId,
 1427    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1428        self.selections_by_transaction.get_mut(&transaction_id)
 1429    }
 1430
 1431    fn push(&mut self, entry: SelectionHistoryEntry) {
 1432        if !entry.selections.is_empty() {
 1433            match self.mode {
 1434                SelectionHistoryMode::Normal => {
 1435                    self.push_undo(entry);
 1436                    self.redo_stack.clear();
 1437                }
 1438                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1439                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1440                SelectionHistoryMode::Skipping => {}
 1441            }
 1442        }
 1443    }
 1444
 1445    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1446        if self
 1447            .undo_stack
 1448            .back()
 1449            .is_none_or(|e| e.selections != entry.selections)
 1450        {
 1451            self.undo_stack.push_back(entry);
 1452            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1453                self.undo_stack.pop_front();
 1454            }
 1455        }
 1456    }
 1457
 1458    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1459        if self
 1460            .redo_stack
 1461            .back()
 1462            .is_none_or(|e| e.selections != entry.selections)
 1463        {
 1464            self.redo_stack.push_back(entry);
 1465            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1466                self.redo_stack.pop_front();
 1467            }
 1468        }
 1469    }
 1470}
 1471
 1472#[derive(Clone, Copy)]
 1473pub struct RowHighlightOptions {
 1474    pub autoscroll: bool,
 1475    pub include_gutter: bool,
 1476}
 1477
 1478impl Default for RowHighlightOptions {
 1479    fn default() -> Self {
 1480        Self {
 1481            autoscroll: Default::default(),
 1482            include_gutter: true,
 1483        }
 1484    }
 1485}
 1486
 1487struct RowHighlight {
 1488    index: usize,
 1489    range: Range<Anchor>,
 1490    color: Hsla,
 1491    options: RowHighlightOptions,
 1492    type_id: TypeId,
 1493}
 1494
 1495#[derive(Clone, Debug)]
 1496struct AddSelectionsState {
 1497    groups: Vec<AddSelectionsGroup>,
 1498}
 1499
 1500#[derive(Clone, Debug)]
 1501struct AddSelectionsGroup {
 1502    above: bool,
 1503    stack: Vec<usize>,
 1504}
 1505
 1506#[derive(Clone)]
 1507struct SelectNextState {
 1508    query: AhoCorasick,
 1509    wordwise: bool,
 1510    done: bool,
 1511}
 1512
 1513impl std::fmt::Debug for SelectNextState {
 1514    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1515        f.debug_struct(std::any::type_name::<Self>())
 1516            .field("wordwise", &self.wordwise)
 1517            .field("done", &self.done)
 1518            .finish()
 1519    }
 1520}
 1521
 1522#[derive(Debug)]
 1523struct AutocloseRegion {
 1524    selection_id: usize,
 1525    range: Range<Anchor>,
 1526    pair: BracketPair,
 1527}
 1528
 1529#[derive(Debug)]
 1530struct SnippetState {
 1531    ranges: Vec<Vec<Range<Anchor>>>,
 1532    active_index: usize,
 1533    choices: Vec<Option<Vec<String>>>,
 1534}
 1535
 1536#[doc(hidden)]
 1537pub struct RenameState {
 1538    pub range: Range<Anchor>,
 1539    pub old_name: Arc<str>,
 1540    pub editor: Entity<Editor>,
 1541    block_id: CustomBlockId,
 1542}
 1543
 1544struct InvalidationStack<T>(Vec<T>);
 1545
 1546struct RegisteredEditPredictionProvider {
 1547    provider: Arc<dyn EditPredictionProviderHandle>,
 1548    _subscription: Subscription,
 1549}
 1550
 1551#[derive(Debug, PartialEq, Eq)]
 1552pub struct ActiveDiagnosticGroup {
 1553    pub active_range: Range<Anchor>,
 1554    pub active_message: String,
 1555    pub group_id: usize,
 1556    pub blocks: HashSet<CustomBlockId>,
 1557}
 1558
 1559#[derive(Debug, PartialEq, Eq)]
 1560
 1561pub(crate) enum ActiveDiagnostic {
 1562    None,
 1563    All,
 1564    Group(ActiveDiagnosticGroup),
 1565}
 1566
 1567#[derive(Serialize, Deserialize, Clone, Debug)]
 1568pub struct ClipboardSelection {
 1569    /// The number of bytes in this selection.
 1570    pub len: usize,
 1571    /// Whether this was a full-line selection.
 1572    pub is_entire_line: bool,
 1573    /// The indentation of the first line when this content was originally copied.
 1574    pub first_line_indent: u32,
 1575}
 1576
 1577// selections, scroll behavior, was newest selection reversed
 1578type SelectSyntaxNodeHistoryState = (
 1579    Box<[Selection<usize>]>,
 1580    SelectSyntaxNodeScrollBehavior,
 1581    bool,
 1582);
 1583
 1584#[derive(Default)]
 1585struct SelectSyntaxNodeHistory {
 1586    stack: Vec<SelectSyntaxNodeHistoryState>,
 1587    // disable temporarily to allow changing selections without losing the stack
 1588    pub disable_clearing: bool,
 1589}
 1590
 1591impl SelectSyntaxNodeHistory {
 1592    pub fn try_clear(&mut self) {
 1593        if !self.disable_clearing {
 1594            self.stack.clear();
 1595        }
 1596    }
 1597
 1598    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1599        self.stack.push(selection);
 1600    }
 1601
 1602    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1603        self.stack.pop()
 1604    }
 1605}
 1606
 1607enum SelectSyntaxNodeScrollBehavior {
 1608    CursorTop,
 1609    FitSelection,
 1610    CursorBottom,
 1611}
 1612
 1613#[derive(Debug)]
 1614pub(crate) struct NavigationData {
 1615    cursor_anchor: Anchor,
 1616    cursor_position: Point,
 1617    scroll_anchor: ScrollAnchor,
 1618    scroll_top_row: u32,
 1619}
 1620
 1621#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1622pub enum GotoDefinitionKind {
 1623    Symbol,
 1624    Declaration,
 1625    Type,
 1626    Implementation,
 1627}
 1628
 1629pub enum FormatTarget {
 1630    Buffers(HashSet<Entity<Buffer>>),
 1631    Ranges(Vec<Range<MultiBufferPoint>>),
 1632}
 1633
 1634pub(crate) struct FocusedBlock {
 1635    id: BlockId,
 1636    focus_handle: WeakFocusHandle,
 1637}
 1638
 1639#[derive(Clone)]
 1640enum JumpData {
 1641    MultiBufferRow {
 1642        row: MultiBufferRow,
 1643        line_offset_from_top: u32,
 1644    },
 1645    MultiBufferPoint {
 1646        excerpt_id: ExcerptId,
 1647        position: Point,
 1648        anchor: text::Anchor,
 1649        line_offset_from_top: u32,
 1650    },
 1651}
 1652
 1653pub enum MultibufferSelectionMode {
 1654    First,
 1655    All,
 1656}
 1657
 1658#[derive(Clone, Copy, Debug, Default)]
 1659pub struct RewrapOptions {
 1660    pub override_language_settings: bool,
 1661    pub preserve_existing_whitespace: bool,
 1662}
 1663
 1664impl Editor {
 1665    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1666        let buffer = cx.new(|cx| Buffer::local("", cx));
 1667        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1668        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1669    }
 1670
 1671    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1672        let buffer = cx.new(|cx| Buffer::local("", cx));
 1673        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1674        Self::new(EditorMode::full(), buffer, None, window, cx)
 1675    }
 1676
 1677    pub fn auto_height(
 1678        min_lines: usize,
 1679        max_lines: usize,
 1680        window: &mut Window,
 1681        cx: &mut Context<Self>,
 1682    ) -> Self {
 1683        let buffer = cx.new(|cx| Buffer::local("", cx));
 1684        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1685        Self::new(
 1686            EditorMode::AutoHeight {
 1687                min_lines,
 1688                max_lines: Some(max_lines),
 1689            },
 1690            buffer,
 1691            None,
 1692            window,
 1693            cx,
 1694        )
 1695    }
 1696
 1697    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1698    /// The editor grows as tall as needed to fit its content.
 1699    pub fn auto_height_unbounded(
 1700        min_lines: usize,
 1701        window: &mut Window,
 1702        cx: &mut Context<Self>,
 1703    ) -> Self {
 1704        let buffer = cx.new(|cx| Buffer::local("", cx));
 1705        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1706        Self::new(
 1707            EditorMode::AutoHeight {
 1708                min_lines,
 1709                max_lines: None,
 1710            },
 1711            buffer,
 1712            None,
 1713            window,
 1714            cx,
 1715        )
 1716    }
 1717
 1718    pub fn for_buffer(
 1719        buffer: Entity<Buffer>,
 1720        project: Option<Entity<Project>>,
 1721        window: &mut Window,
 1722        cx: &mut Context<Self>,
 1723    ) -> Self {
 1724        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1725        Self::new(EditorMode::full(), buffer, project, window, cx)
 1726    }
 1727
 1728    pub fn for_multibuffer(
 1729        buffer: Entity<MultiBuffer>,
 1730        project: Option<Entity<Project>>,
 1731        window: &mut Window,
 1732        cx: &mut Context<Self>,
 1733    ) -> Self {
 1734        Self::new(EditorMode::full(), buffer, project, window, cx)
 1735    }
 1736
 1737    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1738        let mut clone = Self::new(
 1739            self.mode.clone(),
 1740            self.buffer.clone(),
 1741            self.project.clone(),
 1742            window,
 1743            cx,
 1744        );
 1745        self.display_map.update(cx, |display_map, cx| {
 1746            let snapshot = display_map.snapshot(cx);
 1747            clone.display_map.update(cx, |display_map, cx| {
 1748                display_map.set_state(&snapshot, cx);
 1749            });
 1750        });
 1751        clone.folds_did_change(cx);
 1752        clone.selections.clone_state(&self.selections);
 1753        clone.scroll_manager.clone_state(&self.scroll_manager);
 1754        clone.searchable = self.searchable;
 1755        clone.read_only = self.read_only;
 1756        clone
 1757    }
 1758
 1759    pub fn new(
 1760        mode: EditorMode,
 1761        buffer: Entity<MultiBuffer>,
 1762        project: Option<Entity<Project>>,
 1763        window: &mut Window,
 1764        cx: &mut Context<Self>,
 1765    ) -> Self {
 1766        Editor::new_internal(mode, buffer, project, None, window, cx)
 1767    }
 1768
 1769    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1770        let multi_buffer = self.buffer().read(cx);
 1771        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1772        let multi_buffer_visible_start = self
 1773            .scroll_manager
 1774            .anchor()
 1775            .anchor
 1776            .to_point(&multi_buffer_snapshot);
 1777        let max_row = multi_buffer_snapshot.max_point().row;
 1778
 1779        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1780        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1781
 1782        if let Some((excerpt_id, buffer_id, buffer)) = multi_buffer.read(cx).as_singleton() {
 1783            let outline_items = buffer
 1784                .outline_items_containing(
 1785                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1786                    true,
 1787                    self.style().map(|style| style.syntax.as_ref()),
 1788                )
 1789                .into_iter()
 1790                .map(|outline_item| OutlineItem {
 1791                    depth: outline_item.depth,
 1792                    range: Anchor::range_in_buffer(*excerpt_id, buffer_id, outline_item.range),
 1793                    source_range_for_text: Anchor::range_in_buffer(
 1794                        *excerpt_id,
 1795                        buffer_id,
 1796                        outline_item.source_range_for_text,
 1797                    ),
 1798                    text: outline_item.text,
 1799                    highlight_ranges: outline_item.highlight_ranges,
 1800                    name_ranges: outline_item.name_ranges,
 1801                    body_range: outline_item
 1802                        .body_range
 1803                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1804                    annotation_range: outline_item
 1805                        .annotation_range
 1806                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1807                });
 1808            return Some(outline_items.collect());
 1809        }
 1810
 1811        None
 1812    }
 1813
 1814    fn new_internal(
 1815        mode: EditorMode,
 1816        multi_buffer: Entity<MultiBuffer>,
 1817        project: Option<Entity<Project>>,
 1818        display_map: Option<Entity<DisplayMap>>,
 1819        window: &mut Window,
 1820        cx: &mut Context<Self>,
 1821    ) -> Self {
 1822        debug_assert!(
 1823            display_map.is_none() || mode.is_minimap(),
 1824            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1825        );
 1826
 1827        let full_mode = mode.is_full();
 1828        let is_minimap = mode.is_minimap();
 1829        let diagnostics_max_severity = if full_mode {
 1830            EditorSettings::get_global(cx)
 1831                .diagnostics_max_severity
 1832                .unwrap_or(DiagnosticSeverity::Hint)
 1833        } else {
 1834            DiagnosticSeverity::Off
 1835        };
 1836        let style = window.text_style();
 1837        let font_size = style.font_size.to_pixels(window.rem_size());
 1838        let editor = cx.entity().downgrade();
 1839        let fold_placeholder = FoldPlaceholder {
 1840            constrain_width: false,
 1841            render: Arc::new(move |fold_id, fold_range, cx| {
 1842                let editor = editor.clone();
 1843                div()
 1844                    .id(fold_id)
 1845                    .bg(cx.theme().colors().ghost_element_background)
 1846                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1847                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1848                    .rounded_xs()
 1849                    .size_full()
 1850                    .cursor_pointer()
 1851                    .child("")
 1852                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1853                    .on_click(move |_, _window, cx| {
 1854                        editor
 1855                            .update(cx, |editor, cx| {
 1856                                editor.unfold_ranges(
 1857                                    &[fold_range.start..fold_range.end],
 1858                                    true,
 1859                                    false,
 1860                                    cx,
 1861                                );
 1862                                cx.stop_propagation();
 1863                            })
 1864                            .ok();
 1865                    })
 1866                    .into_any()
 1867            }),
 1868            merge_adjacent: true,
 1869            ..FoldPlaceholder::default()
 1870        };
 1871        let display_map = display_map.unwrap_or_else(|| {
 1872            cx.new(|cx| {
 1873                DisplayMap::new(
 1874                    multi_buffer.clone(),
 1875                    style.font(),
 1876                    font_size,
 1877                    None,
 1878                    FILE_HEADER_HEIGHT,
 1879                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1880                    fold_placeholder,
 1881                    diagnostics_max_severity,
 1882                    cx,
 1883                )
 1884            })
 1885        });
 1886
 1887        let selections = SelectionsCollection::new();
 1888
 1889        let blink_manager = cx.new(|cx| {
 1890            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1891            if is_minimap {
 1892                blink_manager.disable(cx);
 1893            }
 1894            blink_manager
 1895        });
 1896
 1897        let soft_wrap_mode_override =
 1898            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1899
 1900        let mut project_subscriptions = Vec::new();
 1901        if full_mode && let Some(project) = project.as_ref() {
 1902            project_subscriptions.push(cx.subscribe_in(
 1903                project,
 1904                window,
 1905                |editor, _, event, window, cx| match event {
 1906                    project::Event::RefreshCodeLens => {
 1907                        // we always query lens with actions, without storing them, always refreshing them
 1908                    }
 1909                    project::Event::RefreshInlayHints {
 1910                        server_id,
 1911                        request_id,
 1912                    } => {
 1913                        editor.refresh_inlay_hints(
 1914                            InlayHintRefreshReason::RefreshRequested {
 1915                                server_id: *server_id,
 1916                                request_id: *request_id,
 1917                            },
 1918                            cx,
 1919                        );
 1920                    }
 1921                    project::Event::LanguageServerRemoved(..) => {
 1922                        if editor.tasks_update_task.is_none() {
 1923                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1924                        }
 1925                        editor.registered_buffers.clear();
 1926                        editor.register_visible_buffers(cx);
 1927                    }
 1928                    project::Event::LanguageServerAdded(..) => {
 1929                        if editor.tasks_update_task.is_none() {
 1930                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1931                        }
 1932                    }
 1933                    project::Event::SnippetEdit(id, snippet_edits) => {
 1934                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1935                            let focus_handle = editor.focus_handle(cx);
 1936                            if focus_handle.is_focused(window) {
 1937                                let snapshot = buffer.read(cx).snapshot();
 1938                                for (range, snippet) in snippet_edits {
 1939                                    let editor_range =
 1940                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1941                                    editor
 1942                                        .insert_snippet(
 1943                                            &[editor_range],
 1944                                            snippet.clone(),
 1945                                            window,
 1946                                            cx,
 1947                                        )
 1948                                        .ok();
 1949                                }
 1950                            }
 1951                        }
 1952                    }
 1953                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1954                        let buffer_id = *buffer_id;
 1955                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1956                            editor.register_buffer(buffer_id, cx);
 1957                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1958                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1959                            refresh_linked_ranges(editor, window, cx);
 1960                            editor.refresh_code_actions(window, cx);
 1961                            editor.refresh_document_highlights(cx);
 1962                        }
 1963                    }
 1964
 1965                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1966                        let Some(workspace) = editor.workspace() else {
 1967                            return;
 1968                        };
 1969                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1970                        else {
 1971                            return;
 1972                        };
 1973
 1974                        if active_editor.entity_id() == cx.entity_id() {
 1975                            let entity_id = cx.entity_id();
 1976                            workspace.update(cx, |this, cx| {
 1977                                this.panes_mut()
 1978                                    .iter_mut()
 1979                                    .filter(|pane| pane.entity_id() != entity_id)
 1980                                    .for_each(|p| {
 1981                                        p.update(cx, |pane, _| {
 1982                                            pane.nav_history_mut().rename_item(
 1983                                                entity_id,
 1984                                                project_path.clone(),
 1985                                                abs_path.clone().into(),
 1986                                            );
 1987                                        })
 1988                                    });
 1989                            });
 1990                            let edited_buffers_already_open = {
 1991                                let other_editors: Vec<Entity<Editor>> = workspace
 1992                                    .read(cx)
 1993                                    .panes()
 1994                                    .iter()
 1995                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1996                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1997                                    .collect();
 1998
 1999                                transaction.0.keys().all(|buffer| {
 2000                                    other_editors.iter().any(|editor| {
 2001                                        let multi_buffer = editor.read(cx).buffer();
 2002                                        multi_buffer.read(cx).is_singleton()
 2003                                            && multi_buffer.read(cx).as_singleton().map_or(
 2004                                                false,
 2005                                                |singleton| {
 2006                                                    singleton.entity_id() == buffer.entity_id()
 2007                                                },
 2008                                            )
 2009                                    })
 2010                                })
 2011                            };
 2012                            if !edited_buffers_already_open {
 2013                                let workspace = workspace.downgrade();
 2014                                let transaction = transaction.clone();
 2015                                cx.defer_in(window, move |_, window, cx| {
 2016                                    cx.spawn_in(window, async move |editor, cx| {
 2017                                        Self::open_project_transaction(
 2018                                            &editor,
 2019                                            workspace,
 2020                                            transaction,
 2021                                            "Rename".to_string(),
 2022                                            cx,
 2023                                        )
 2024                                        .await
 2025                                        .ok()
 2026                                    })
 2027                                    .detach();
 2028                                });
 2029                            }
 2030                        }
 2031                    }
 2032
 2033                    _ => {}
 2034                },
 2035            ));
 2036            if let Some(task_inventory) = project
 2037                .read(cx)
 2038                .task_store()
 2039                .read(cx)
 2040                .task_inventory()
 2041                .cloned()
 2042            {
 2043                project_subscriptions.push(cx.observe_in(
 2044                    &task_inventory,
 2045                    window,
 2046                    |editor, _, window, cx| {
 2047                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2048                    },
 2049                ));
 2050            };
 2051
 2052            project_subscriptions.push(cx.subscribe_in(
 2053                &project.read(cx).breakpoint_store(),
 2054                window,
 2055                |editor, _, event, window, cx| match event {
 2056                    BreakpointStoreEvent::ClearDebugLines => {
 2057                        editor.clear_row_highlights::<ActiveDebugLine>();
 2058                        editor.refresh_inline_values(cx);
 2059                    }
 2060                    BreakpointStoreEvent::SetDebugLine => {
 2061                        if editor.go_to_active_debug_line(window, cx) {
 2062                            cx.stop_propagation();
 2063                        }
 2064
 2065                        editor.refresh_inline_values(cx);
 2066                    }
 2067                    _ => {}
 2068                },
 2069            ));
 2070            let git_store = project.read(cx).git_store().clone();
 2071            let project = project.clone();
 2072            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2073                if let GitStoreEvent::RepositoryAdded = event {
 2074                    this.load_diff_task = Some(
 2075                        update_uncommitted_diff_for_buffer(
 2076                            cx.entity(),
 2077                            &project,
 2078                            this.buffer.read(cx).all_buffers(),
 2079                            this.buffer.clone(),
 2080                            cx,
 2081                        )
 2082                        .shared(),
 2083                    );
 2084                }
 2085            }));
 2086        }
 2087
 2088        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2089
 2090        let inlay_hint_settings =
 2091            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2092        let focus_handle = cx.focus_handle();
 2093        if !is_minimap {
 2094            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2095                .detach();
 2096            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2097                .detach();
 2098            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2099                .detach();
 2100            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2101                .detach();
 2102            cx.observe_pending_input(window, Self::observe_pending_input)
 2103                .detach();
 2104        }
 2105
 2106        let show_indent_guides =
 2107            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2108                Some(false)
 2109            } else {
 2110                None
 2111            };
 2112
 2113        let breakpoint_store = match (&mode, project.as_ref()) {
 2114            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2115            _ => None,
 2116        };
 2117
 2118        let mut code_action_providers = Vec::new();
 2119        let mut load_uncommitted_diff = None;
 2120        if let Some(project) = project.clone() {
 2121            load_uncommitted_diff = Some(
 2122                update_uncommitted_diff_for_buffer(
 2123                    cx.entity(),
 2124                    &project,
 2125                    multi_buffer.read(cx).all_buffers(),
 2126                    multi_buffer.clone(),
 2127                    cx,
 2128                )
 2129                .shared(),
 2130            );
 2131            code_action_providers.push(Rc::new(project) as Rc<_>);
 2132        }
 2133
 2134        let mut editor = Self {
 2135            focus_handle,
 2136            show_cursor_when_unfocused: false,
 2137            last_focused_descendant: None,
 2138            buffer: multi_buffer.clone(),
 2139            display_map: display_map.clone(),
 2140            placeholder_display_map: None,
 2141            selections,
 2142            scroll_manager: ScrollManager::new(cx),
 2143            columnar_selection_state: None,
 2144            add_selections_state: None,
 2145            select_next_state: None,
 2146            select_prev_state: None,
 2147            selection_history: SelectionHistory::default(),
 2148            defer_selection_effects: false,
 2149            deferred_selection_effects_state: None,
 2150            autoclose_regions: Vec::new(),
 2151            snippet_stack: InvalidationStack::default(),
 2152            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2153            ime_transaction: None,
 2154            active_diagnostics: ActiveDiagnostic::None,
 2155            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2156            inline_diagnostics_update: Task::ready(()),
 2157            inline_diagnostics: Vec::new(),
 2158            soft_wrap_mode_override,
 2159            diagnostics_max_severity,
 2160            hard_wrap: None,
 2161            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2162            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2163            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2164            project,
 2165            blink_manager: blink_manager.clone(),
 2166            show_local_selections: true,
 2167            show_scrollbars: ScrollbarAxes {
 2168                horizontal: full_mode,
 2169                vertical: full_mode,
 2170            },
 2171            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2172            offset_content: !matches!(mode, EditorMode::SingleLine),
 2173            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2174            show_gutter: full_mode,
 2175            show_line_numbers: (!full_mode).then_some(false),
 2176            use_relative_line_numbers: None,
 2177            disable_expand_excerpt_buttons: !full_mode,
 2178            show_git_diff_gutter: None,
 2179            show_code_actions: None,
 2180            show_runnables: None,
 2181            show_breakpoints: None,
 2182            show_wrap_guides: None,
 2183            show_indent_guides,
 2184            highlight_order: 0,
 2185            highlighted_rows: HashMap::default(),
 2186            background_highlights: HashMap::default(),
 2187            gutter_highlights: HashMap::default(),
 2188            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2189            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2190            nav_history: None,
 2191            context_menu: RefCell::new(None),
 2192            context_menu_options: None,
 2193            mouse_context_menu: None,
 2194            completion_tasks: Vec::new(),
 2195            inline_blame_popover: None,
 2196            inline_blame_popover_show_task: None,
 2197            signature_help_state: SignatureHelpState::default(),
 2198            auto_signature_help: None,
 2199            find_all_references_task_sources: Vec::new(),
 2200            next_completion_id: 0,
 2201            next_inlay_id: 0,
 2202            code_action_providers,
 2203            available_code_actions: None,
 2204            code_actions_task: None,
 2205            quick_selection_highlight_task: None,
 2206            debounced_selection_highlight_task: None,
 2207            document_highlights_task: None,
 2208            linked_editing_range_task: None,
 2209            pending_rename: None,
 2210            searchable: !is_minimap,
 2211            cursor_shape: EditorSettings::get_global(cx)
 2212                .cursor_shape
 2213                .unwrap_or_default(),
 2214            current_line_highlight: None,
 2215            autoindent_mode: Some(AutoindentMode::EachLine),
 2216
 2217            workspace: None,
 2218            input_enabled: !is_minimap,
 2219            use_modal_editing: full_mode,
 2220            read_only: is_minimap,
 2221            use_autoclose: true,
 2222            use_auto_surround: true,
 2223            auto_replace_emoji_shortcode: false,
 2224            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2225            leader_id: None,
 2226            remote_id: None,
 2227            hover_state: HoverState::default(),
 2228            pending_mouse_down: None,
 2229            hovered_link_state: None,
 2230            edit_prediction_provider: None,
 2231            active_edit_prediction: None,
 2232            stale_edit_prediction_in_menu: None,
 2233            edit_prediction_preview: EditPredictionPreview::Inactive {
 2234                released_too_fast: false,
 2235            },
 2236            inline_diagnostics_enabled: full_mode,
 2237            diagnostics_enabled: full_mode,
 2238            word_completions_enabled: full_mode,
 2239            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2240            gutter_hovered: false,
 2241            pixel_position_of_newest_cursor: None,
 2242            last_bounds: None,
 2243            last_position_map: None,
 2244            expect_bounds_change: None,
 2245            gutter_dimensions: GutterDimensions::default(),
 2246            style: None,
 2247            show_cursor_names: false,
 2248            hovered_cursors: HashMap::default(),
 2249            next_editor_action_id: EditorActionId::default(),
 2250            editor_actions: Rc::default(),
 2251            edit_predictions_hidden_for_vim_mode: false,
 2252            show_edit_predictions_override: None,
 2253            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2254            edit_prediction_settings: EditPredictionSettings::Disabled,
 2255            edit_prediction_indent_conflict: false,
 2256            edit_prediction_requires_modifier_in_indent_conflict: true,
 2257            custom_context_menu: None,
 2258            show_git_blame_gutter: false,
 2259            show_git_blame_inline: false,
 2260            show_selection_menu: None,
 2261            show_git_blame_inline_delay_task: None,
 2262            git_blame_inline_enabled: full_mode
 2263                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2264            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2265            buffer_serialization: is_minimap.not().then(|| {
 2266                BufferSerialization::new(
 2267                    ProjectSettings::get_global(cx)
 2268                        .session
 2269                        .restore_unsaved_buffers,
 2270                )
 2271            }),
 2272            blame: None,
 2273            blame_subscription: None,
 2274            tasks: BTreeMap::default(),
 2275
 2276            breakpoint_store,
 2277            gutter_breakpoint_indicator: (None, None),
 2278            hovered_diff_hunk_row: None,
 2279            _subscriptions: (!is_minimap)
 2280                .then(|| {
 2281                    vec![
 2282                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2283                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2284                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2285                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2286                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2287                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2288                        cx.observe_window_activation(window, |editor, window, cx| {
 2289                            let active = window.is_window_active();
 2290                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2291                                if active {
 2292                                    blink_manager.enable(cx);
 2293                                } else {
 2294                                    blink_manager.disable(cx);
 2295                                }
 2296                            });
 2297                            if active {
 2298                                editor.show_mouse_cursor(cx);
 2299                            }
 2300                        }),
 2301                    ]
 2302                })
 2303                .unwrap_or_default(),
 2304            tasks_update_task: None,
 2305            pull_diagnostics_task: Task::ready(()),
 2306            colors: None,
 2307            refresh_colors_task: Task::ready(()),
 2308            inlay_hints: None,
 2309            next_color_inlay_id: 0,
 2310            post_scroll_update: Task::ready(()),
 2311            linked_edit_ranges: Default::default(),
 2312            in_project_search: false,
 2313            previous_search_ranges: None,
 2314            breadcrumb_header: None,
 2315            focused_block: None,
 2316            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2317            addons: HashMap::default(),
 2318            registered_buffers: HashMap::default(),
 2319            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2320            selection_mark_mode: false,
 2321            toggle_fold_multiple_buffers: Task::ready(()),
 2322            serialize_selections: Task::ready(()),
 2323            serialize_folds: Task::ready(()),
 2324            text_style_refinement: None,
 2325            load_diff_task: load_uncommitted_diff,
 2326            temporary_diff_override: false,
 2327            mouse_cursor_hidden: false,
 2328            minimap: None,
 2329            hide_mouse_mode: EditorSettings::get_global(cx)
 2330                .hide_mouse
 2331                .unwrap_or_default(),
 2332            change_list: ChangeList::new(),
 2333            mode,
 2334            selection_drag_state: SelectionDragState::None,
 2335            folding_newlines: Task::ready(()),
 2336            lookup_key: None,
 2337            select_next_is_case_sensitive: None,
 2338        };
 2339
 2340        if is_minimap {
 2341            return editor;
 2342        }
 2343
 2344        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2345            editor
 2346                ._subscriptions
 2347                .push(cx.observe(breakpoints, |_, _, cx| {
 2348                    cx.notify();
 2349                }));
 2350        }
 2351        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2352        editor._subscriptions.extend(project_subscriptions);
 2353
 2354        editor._subscriptions.push(cx.subscribe_in(
 2355            &cx.entity(),
 2356            window,
 2357            |editor, _, e: &EditorEvent, window, cx| match e {
 2358                EditorEvent::ScrollPositionChanged { local, .. } => {
 2359                    if *local {
 2360                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2361                        editor.inline_blame_popover.take();
 2362                        let new_anchor = editor.scroll_manager.anchor();
 2363                        let snapshot = editor.snapshot(window, cx);
 2364                        editor.update_restoration_data(cx, move |data| {
 2365                            data.scroll_position = (
 2366                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2367                                new_anchor.offset,
 2368                            );
 2369                        });
 2370
 2371                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2372                            cx.background_executor()
 2373                                .timer(Duration::from_millis(50))
 2374                                .await;
 2375                            editor
 2376                                .update_in(cx, |editor, window, cx| {
 2377                                    editor.register_visible_buffers(cx);
 2378                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2379                                    editor.refresh_inlay_hints(
 2380                                        InlayHintRefreshReason::NewLinesShown,
 2381                                        cx,
 2382                                    );
 2383                                })
 2384                                .ok();
 2385                        });
 2386                    }
 2387                }
 2388                EditorEvent::Edited { .. } => {
 2389                    if vim_flavor(cx).is_none() {
 2390                        let display_map = editor.display_snapshot(cx);
 2391                        let selections = editor.selections.all_adjusted_display(&display_map);
 2392                        let pop_state = editor
 2393                            .change_list
 2394                            .last()
 2395                            .map(|previous| {
 2396                                previous.len() == selections.len()
 2397                                    && previous.iter().enumerate().all(|(ix, p)| {
 2398                                        p.to_display_point(&display_map).row()
 2399                                            == selections[ix].head().row()
 2400                                    })
 2401                            })
 2402                            .unwrap_or(false);
 2403                        let new_positions = selections
 2404                            .into_iter()
 2405                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2406                            .collect();
 2407                        editor
 2408                            .change_list
 2409                            .push_to_change_list(pop_state, new_positions);
 2410                    }
 2411                }
 2412                _ => (),
 2413            },
 2414        ));
 2415
 2416        if let Some(dap_store) = editor
 2417            .project
 2418            .as_ref()
 2419            .map(|project| project.read(cx).dap_store())
 2420        {
 2421            let weak_editor = cx.weak_entity();
 2422
 2423            editor
 2424                ._subscriptions
 2425                .push(
 2426                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2427                        let session_entity = cx.entity();
 2428                        weak_editor
 2429                            .update(cx, |editor, cx| {
 2430                                editor._subscriptions.push(
 2431                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2432                                );
 2433                            })
 2434                            .ok();
 2435                    }),
 2436                );
 2437
 2438            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2439                editor
 2440                    ._subscriptions
 2441                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2442            }
 2443        }
 2444
 2445        // skip adding the initial selection to selection history
 2446        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2447        editor.end_selection(window, cx);
 2448        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2449
 2450        editor.scroll_manager.show_scrollbars(window, cx);
 2451        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2452
 2453        if full_mode {
 2454            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2455            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2456
 2457            if editor.git_blame_inline_enabled {
 2458                editor.start_git_blame_inline(false, window, cx);
 2459            }
 2460
 2461            editor.go_to_active_debug_line(window, cx);
 2462
 2463            editor.minimap =
 2464                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2465            editor.colors = Some(LspColorData::new(cx));
 2466            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2467
 2468            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2469                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2470            }
 2471            editor.update_lsp_data(None, window, cx);
 2472            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2473        }
 2474
 2475        editor
 2476    }
 2477
 2478    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2479        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2480    }
 2481
 2482    pub fn deploy_mouse_context_menu(
 2483        &mut self,
 2484        position: gpui::Point<Pixels>,
 2485        context_menu: Entity<ContextMenu>,
 2486        window: &mut Window,
 2487        cx: &mut Context<Self>,
 2488    ) {
 2489        self.mouse_context_menu = Some(MouseContextMenu::new(
 2490            self,
 2491            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2492            context_menu,
 2493            window,
 2494            cx,
 2495        ));
 2496    }
 2497
 2498    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2499        self.mouse_context_menu
 2500            .as_ref()
 2501            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2502    }
 2503
 2504    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2505        if self
 2506            .selections
 2507            .pending_anchor()
 2508            .is_some_and(|pending_selection| {
 2509                let snapshot = self.buffer().read(cx).snapshot(cx);
 2510                pending_selection.range().includes(range, &snapshot)
 2511            })
 2512        {
 2513            return true;
 2514        }
 2515
 2516        self.selections
 2517            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2518            .into_iter()
 2519            .any(|selection| {
 2520                // This is needed to cover a corner case, if we just check for an existing
 2521                // selection in the fold range, having a cursor at the start of the fold
 2522                // marks it as selected. Non-empty selections don't cause this.
 2523                let length = selection.end - selection.start;
 2524                length > 0
 2525            })
 2526    }
 2527
 2528    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2529        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2530    }
 2531
 2532    fn key_context_internal(
 2533        &self,
 2534        has_active_edit_prediction: bool,
 2535        window: &mut Window,
 2536        cx: &mut App,
 2537    ) -> KeyContext {
 2538        let mut key_context = KeyContext::new_with_defaults();
 2539        key_context.add("Editor");
 2540        let mode = match self.mode {
 2541            EditorMode::SingleLine => "single_line",
 2542            EditorMode::AutoHeight { .. } => "auto_height",
 2543            EditorMode::Minimap { .. } => "minimap",
 2544            EditorMode::Full { .. } => "full",
 2545        };
 2546
 2547        if EditorSettings::jupyter_enabled(cx) {
 2548            key_context.add("jupyter");
 2549        }
 2550
 2551        key_context.set("mode", mode);
 2552        if self.pending_rename.is_some() {
 2553            key_context.add("renaming");
 2554        }
 2555
 2556        if let Some(snippet_stack) = self.snippet_stack.last() {
 2557            key_context.add("in_snippet");
 2558
 2559            if snippet_stack.active_index > 0 {
 2560                key_context.add("has_previous_tabstop");
 2561            }
 2562
 2563            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2564                key_context.add("has_next_tabstop");
 2565            }
 2566        }
 2567
 2568        match self.context_menu.borrow().as_ref() {
 2569            Some(CodeContextMenu::Completions(menu)) => {
 2570                if menu.visible() {
 2571                    key_context.add("menu");
 2572                    key_context.add("showing_completions");
 2573                }
 2574            }
 2575            Some(CodeContextMenu::CodeActions(menu)) => {
 2576                if menu.visible() {
 2577                    key_context.add("menu");
 2578                    key_context.add("showing_code_actions")
 2579                }
 2580            }
 2581            None => {}
 2582        }
 2583
 2584        if self.signature_help_state.has_multiple_signatures() {
 2585            key_context.add("showing_signature_help");
 2586        }
 2587
 2588        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2589        if !self.focus_handle(cx).contains_focused(window, cx)
 2590            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2591        {
 2592            for addon in self.addons.values() {
 2593                addon.extend_key_context(&mut key_context, cx)
 2594            }
 2595        }
 2596
 2597        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2598            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2599                Some(
 2600                    file.full_path(cx)
 2601                        .extension()?
 2602                        .to_string_lossy()
 2603                        .into_owned(),
 2604                )
 2605            }) {
 2606                key_context.set("extension", extension);
 2607            }
 2608        } else {
 2609            key_context.add("multibuffer");
 2610        }
 2611
 2612        if has_active_edit_prediction {
 2613            if self.edit_prediction_in_conflict() {
 2614                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2615            } else {
 2616                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2617                key_context.add("copilot_suggestion");
 2618            }
 2619        }
 2620
 2621        if self.selection_mark_mode {
 2622            key_context.add("selection_mode");
 2623        }
 2624
 2625        let disjoint = self.selections.disjoint_anchors();
 2626        let snapshot = self.snapshot(window, cx);
 2627        let snapshot = snapshot.buffer_snapshot();
 2628        if self.mode == EditorMode::SingleLine
 2629            && let [selection] = disjoint
 2630            && selection.start == selection.end
 2631            && selection.end.to_offset(snapshot) == snapshot.len()
 2632        {
 2633            key_context.add("end_of_input");
 2634        }
 2635
 2636        key_context
 2637    }
 2638
 2639    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2640        self.last_bounds.as_ref()
 2641    }
 2642
 2643    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2644        if self.mouse_cursor_hidden {
 2645            self.mouse_cursor_hidden = false;
 2646            cx.notify();
 2647        }
 2648    }
 2649
 2650    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2651        let hide_mouse_cursor = match origin {
 2652            HideMouseCursorOrigin::TypingAction => {
 2653                matches!(
 2654                    self.hide_mouse_mode,
 2655                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2656                )
 2657            }
 2658            HideMouseCursorOrigin::MovementAction => {
 2659                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2660            }
 2661        };
 2662        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2663            self.mouse_cursor_hidden = hide_mouse_cursor;
 2664            cx.notify();
 2665        }
 2666    }
 2667
 2668    pub fn edit_prediction_in_conflict(&self) -> bool {
 2669        if !self.show_edit_predictions_in_menu() {
 2670            return false;
 2671        }
 2672
 2673        let showing_completions = self
 2674            .context_menu
 2675            .borrow()
 2676            .as_ref()
 2677            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2678
 2679        showing_completions
 2680            || self.edit_prediction_requires_modifier()
 2681            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2682            // bindings to insert tab characters.
 2683            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2684    }
 2685
 2686    pub fn accept_edit_prediction_keybind(
 2687        &self,
 2688        accept_partial: bool,
 2689        window: &mut Window,
 2690        cx: &mut App,
 2691    ) -> AcceptEditPredictionBinding {
 2692        let key_context = self.key_context_internal(true, window, cx);
 2693        let in_conflict = self.edit_prediction_in_conflict();
 2694
 2695        let bindings = if accept_partial {
 2696            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2697        } else {
 2698            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2699        };
 2700
 2701        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2702        // just the first one.
 2703        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2704            !in_conflict
 2705                || binding
 2706                    .keystrokes()
 2707                    .first()
 2708                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2709        }))
 2710    }
 2711
 2712    pub fn new_file(
 2713        workspace: &mut Workspace,
 2714        _: &workspace::NewFile,
 2715        window: &mut Window,
 2716        cx: &mut Context<Workspace>,
 2717    ) {
 2718        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2719            "Failed to create buffer",
 2720            window,
 2721            cx,
 2722            |e, _, _| match e.error_code() {
 2723                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2724                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2725                e.error_tag("required").unwrap_or("the latest version")
 2726            )),
 2727                _ => None,
 2728            },
 2729        );
 2730    }
 2731
 2732    pub fn new_in_workspace(
 2733        workspace: &mut Workspace,
 2734        window: &mut Window,
 2735        cx: &mut Context<Workspace>,
 2736    ) -> Task<Result<Entity<Editor>>> {
 2737        let project = workspace.project().clone();
 2738        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2739
 2740        cx.spawn_in(window, async move |workspace, cx| {
 2741            let buffer = create.await?;
 2742            workspace.update_in(cx, |workspace, window, cx| {
 2743                let editor =
 2744                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2745                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2746                editor
 2747            })
 2748        })
 2749    }
 2750
 2751    fn new_file_vertical(
 2752        workspace: &mut Workspace,
 2753        _: &workspace::NewFileSplitVertical,
 2754        window: &mut Window,
 2755        cx: &mut Context<Workspace>,
 2756    ) {
 2757        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2758    }
 2759
 2760    fn new_file_horizontal(
 2761        workspace: &mut Workspace,
 2762        _: &workspace::NewFileSplitHorizontal,
 2763        window: &mut Window,
 2764        cx: &mut Context<Workspace>,
 2765    ) {
 2766        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2767    }
 2768
 2769    fn new_file_split(
 2770        workspace: &mut Workspace,
 2771        action: &workspace::NewFileSplit,
 2772        window: &mut Window,
 2773        cx: &mut Context<Workspace>,
 2774    ) {
 2775        Self::new_file_in_direction(workspace, action.0, window, cx)
 2776    }
 2777
 2778    fn new_file_in_direction(
 2779        workspace: &mut Workspace,
 2780        direction: SplitDirection,
 2781        window: &mut Window,
 2782        cx: &mut Context<Workspace>,
 2783    ) {
 2784        let project = workspace.project().clone();
 2785        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2786
 2787        cx.spawn_in(window, async move |workspace, cx| {
 2788            let buffer = create.await?;
 2789            workspace.update_in(cx, move |workspace, window, cx| {
 2790                workspace.split_item(
 2791                    direction,
 2792                    Box::new(
 2793                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2794                    ),
 2795                    window,
 2796                    cx,
 2797                )
 2798            })?;
 2799            anyhow::Ok(())
 2800        })
 2801        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2802            match e.error_code() {
 2803                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2804                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2805                e.error_tag("required").unwrap_or("the latest version")
 2806            )),
 2807                _ => None,
 2808            }
 2809        });
 2810    }
 2811
 2812    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2813        self.leader_id
 2814    }
 2815
 2816    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2817        &self.buffer
 2818    }
 2819
 2820    pub fn project(&self) -> Option<&Entity<Project>> {
 2821        self.project.as_ref()
 2822    }
 2823
 2824    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2825        self.workspace.as_ref()?.0.upgrade()
 2826    }
 2827
 2828    /// Returns the workspace serialization ID if this editor should be serialized.
 2829    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2830        self.workspace
 2831            .as_ref()
 2832            .filter(|_| self.should_serialize_buffer())
 2833            .and_then(|workspace| workspace.1)
 2834    }
 2835
 2836    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2837        self.buffer().read(cx).title(cx)
 2838    }
 2839
 2840    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2841        let git_blame_gutter_max_author_length = self
 2842            .render_git_blame_gutter(cx)
 2843            .then(|| {
 2844                if let Some(blame) = self.blame.as_ref() {
 2845                    let max_author_length =
 2846                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2847                    Some(max_author_length)
 2848                } else {
 2849                    None
 2850                }
 2851            })
 2852            .flatten();
 2853
 2854        EditorSnapshot {
 2855            mode: self.mode.clone(),
 2856            show_gutter: self.show_gutter,
 2857            show_line_numbers: self.show_line_numbers,
 2858            show_git_diff_gutter: self.show_git_diff_gutter,
 2859            show_code_actions: self.show_code_actions,
 2860            show_runnables: self.show_runnables,
 2861            show_breakpoints: self.show_breakpoints,
 2862            git_blame_gutter_max_author_length,
 2863            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2864            placeholder_display_snapshot: self
 2865                .placeholder_display_map
 2866                .as_ref()
 2867                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2868            scroll_anchor: self.scroll_manager.anchor(),
 2869            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2870            is_focused: self.focus_handle.is_focused(window),
 2871            current_line_highlight: self
 2872                .current_line_highlight
 2873                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2874            gutter_hovered: self.gutter_hovered,
 2875        }
 2876    }
 2877
 2878    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2879        self.buffer.read(cx).language_at(point, cx)
 2880    }
 2881
 2882    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2883        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2884    }
 2885
 2886    pub fn active_excerpt(
 2887        &self,
 2888        cx: &App,
 2889    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2890        self.buffer
 2891            .read(cx)
 2892            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2893    }
 2894
 2895    pub fn mode(&self) -> &EditorMode {
 2896        &self.mode
 2897    }
 2898
 2899    pub fn set_mode(&mut self, mode: EditorMode) {
 2900        self.mode = mode;
 2901    }
 2902
 2903    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2904        self.collaboration_hub.as_deref()
 2905    }
 2906
 2907    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2908        self.collaboration_hub = Some(hub);
 2909    }
 2910
 2911    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2912        self.in_project_search = in_project_search;
 2913    }
 2914
 2915    pub fn set_custom_context_menu(
 2916        &mut self,
 2917        f: impl 'static
 2918        + Fn(
 2919            &mut Self,
 2920            DisplayPoint,
 2921            &mut Window,
 2922            &mut Context<Self>,
 2923        ) -> Option<Entity<ui::ContextMenu>>,
 2924    ) {
 2925        self.custom_context_menu = Some(Box::new(f))
 2926    }
 2927
 2928    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2929        self.completion_provider = provider;
 2930    }
 2931
 2932    #[cfg(any(test, feature = "test-support"))]
 2933    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2934        self.completion_provider.clone()
 2935    }
 2936
 2937    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2938        self.semantics_provider.clone()
 2939    }
 2940
 2941    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2942        self.semantics_provider = provider;
 2943    }
 2944
 2945    pub fn set_edit_prediction_provider<T>(
 2946        &mut self,
 2947        provider: Option<Entity<T>>,
 2948        window: &mut Window,
 2949        cx: &mut Context<Self>,
 2950    ) where
 2951        T: EditPredictionProvider,
 2952    {
 2953        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2954            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2955                if this.focus_handle.is_focused(window) {
 2956                    this.update_visible_edit_prediction(window, cx);
 2957                }
 2958            }),
 2959            provider: Arc::new(provider),
 2960        });
 2961        self.update_edit_prediction_settings(cx);
 2962        self.refresh_edit_prediction(false, false, window, cx);
 2963    }
 2964
 2965    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2966        self.placeholder_display_map
 2967            .as_ref()
 2968            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2969    }
 2970
 2971    pub fn set_placeholder_text(
 2972        &mut self,
 2973        placeholder_text: &str,
 2974        window: &mut Window,
 2975        cx: &mut Context<Self>,
 2976    ) {
 2977        let multibuffer = cx
 2978            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2979
 2980        let style = window.text_style();
 2981
 2982        self.placeholder_display_map = Some(cx.new(|cx| {
 2983            DisplayMap::new(
 2984                multibuffer,
 2985                style.font(),
 2986                style.font_size.to_pixels(window.rem_size()),
 2987                None,
 2988                FILE_HEADER_HEIGHT,
 2989                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2990                Default::default(),
 2991                DiagnosticSeverity::Off,
 2992                cx,
 2993            )
 2994        }));
 2995        cx.notify();
 2996    }
 2997
 2998    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2999        self.cursor_shape = cursor_shape;
 3000
 3001        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3002        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3003
 3004        cx.notify();
 3005    }
 3006
 3007    pub fn set_current_line_highlight(
 3008        &mut self,
 3009        current_line_highlight: Option<CurrentLineHighlight>,
 3010    ) {
 3011        self.current_line_highlight = current_line_highlight;
 3012    }
 3013
 3014    pub fn range_for_match<T: std::marker::Copy>(
 3015        &self,
 3016        range: &Range<T>,
 3017        collapse: bool,
 3018    ) -> Range<T> {
 3019        if collapse {
 3020            return range.start..range.start;
 3021        }
 3022        range.clone()
 3023    }
 3024
 3025    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3026        if self.display_map.read(cx).clip_at_line_ends != clip {
 3027            self.display_map
 3028                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3029        }
 3030    }
 3031
 3032    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3033        self.input_enabled = input_enabled;
 3034    }
 3035
 3036    pub fn set_edit_predictions_hidden_for_vim_mode(
 3037        &mut self,
 3038        hidden: bool,
 3039        window: &mut Window,
 3040        cx: &mut Context<Self>,
 3041    ) {
 3042        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3043            self.edit_predictions_hidden_for_vim_mode = hidden;
 3044            if hidden {
 3045                self.update_visible_edit_prediction(window, cx);
 3046            } else {
 3047                self.refresh_edit_prediction(true, false, window, cx);
 3048            }
 3049        }
 3050    }
 3051
 3052    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3053        self.menu_edit_predictions_policy = value;
 3054    }
 3055
 3056    pub fn set_autoindent(&mut self, autoindent: bool) {
 3057        if autoindent {
 3058            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3059        } else {
 3060            self.autoindent_mode = None;
 3061        }
 3062    }
 3063
 3064    pub fn read_only(&self, cx: &App) -> bool {
 3065        self.read_only || self.buffer.read(cx).read_only()
 3066    }
 3067
 3068    pub fn set_read_only(&mut self, read_only: bool) {
 3069        self.read_only = read_only;
 3070    }
 3071
 3072    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3073        self.use_autoclose = autoclose;
 3074    }
 3075
 3076    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3077        self.use_auto_surround = auto_surround;
 3078    }
 3079
 3080    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3081        self.auto_replace_emoji_shortcode = auto_replace;
 3082    }
 3083
 3084    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3085        self.buffer_serialization = should_serialize.then(|| {
 3086            BufferSerialization::new(
 3087                ProjectSettings::get_global(cx)
 3088                    .session
 3089                    .restore_unsaved_buffers,
 3090            )
 3091        })
 3092    }
 3093
 3094    fn should_serialize_buffer(&self) -> bool {
 3095        self.buffer_serialization.is_some()
 3096    }
 3097
 3098    pub fn toggle_edit_predictions(
 3099        &mut self,
 3100        _: &ToggleEditPrediction,
 3101        window: &mut Window,
 3102        cx: &mut Context<Self>,
 3103    ) {
 3104        if self.show_edit_predictions_override.is_some() {
 3105            self.set_show_edit_predictions(None, window, cx);
 3106        } else {
 3107            let show_edit_predictions = !self.edit_predictions_enabled();
 3108            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3109        }
 3110    }
 3111
 3112    pub fn set_show_edit_predictions(
 3113        &mut self,
 3114        show_edit_predictions: Option<bool>,
 3115        window: &mut Window,
 3116        cx: &mut Context<Self>,
 3117    ) {
 3118        self.show_edit_predictions_override = show_edit_predictions;
 3119        self.update_edit_prediction_settings(cx);
 3120
 3121        if let Some(false) = show_edit_predictions {
 3122            self.discard_edit_prediction(false, cx);
 3123        } else {
 3124            self.refresh_edit_prediction(false, true, window, cx);
 3125        }
 3126    }
 3127
 3128    fn edit_predictions_disabled_in_scope(
 3129        &self,
 3130        buffer: &Entity<Buffer>,
 3131        buffer_position: language::Anchor,
 3132        cx: &App,
 3133    ) -> bool {
 3134        let snapshot = buffer.read(cx).snapshot();
 3135        let settings = snapshot.settings_at(buffer_position, cx);
 3136
 3137        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3138            return false;
 3139        };
 3140
 3141        scope.override_name().is_some_and(|scope_name| {
 3142            settings
 3143                .edit_predictions_disabled_in
 3144                .iter()
 3145                .any(|s| s == scope_name)
 3146        })
 3147    }
 3148
 3149    pub fn set_use_modal_editing(&mut self, to: bool) {
 3150        self.use_modal_editing = to;
 3151    }
 3152
 3153    pub fn use_modal_editing(&self) -> bool {
 3154        self.use_modal_editing
 3155    }
 3156
 3157    fn selections_did_change(
 3158        &mut self,
 3159        local: bool,
 3160        old_cursor_position: &Anchor,
 3161        effects: SelectionEffects,
 3162        window: &mut Window,
 3163        cx: &mut Context<Self>,
 3164    ) {
 3165        window.invalidate_character_coordinates();
 3166
 3167        // Copy selections to primary selection buffer
 3168        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3169        if local {
 3170            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3171            let buffer_handle = self.buffer.read(cx).read(cx);
 3172
 3173            let mut text = String::new();
 3174            for (index, selection) in selections.iter().enumerate() {
 3175                let text_for_selection = buffer_handle
 3176                    .text_for_range(selection.start..selection.end)
 3177                    .collect::<String>();
 3178
 3179                text.push_str(&text_for_selection);
 3180                if index != selections.len() - 1 {
 3181                    text.push('\n');
 3182                }
 3183            }
 3184
 3185            if !text.is_empty() {
 3186                cx.write_to_primary(ClipboardItem::new_string(text));
 3187            }
 3188        }
 3189
 3190        let selection_anchors = self.selections.disjoint_anchors_arc();
 3191
 3192        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3193            self.buffer.update(cx, |buffer, cx| {
 3194                buffer.set_active_selections(
 3195                    &selection_anchors,
 3196                    self.selections.line_mode(),
 3197                    self.cursor_shape,
 3198                    cx,
 3199                )
 3200            });
 3201        }
 3202        let display_map = self
 3203            .display_map
 3204            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3205        let buffer = display_map.buffer_snapshot();
 3206        if self.selections.count() == 1 {
 3207            self.add_selections_state = None;
 3208        }
 3209        self.select_next_state = None;
 3210        self.select_prev_state = None;
 3211        self.select_syntax_node_history.try_clear();
 3212        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3213        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3214        self.take_rename(false, window, cx);
 3215
 3216        let newest_selection = self.selections.newest_anchor();
 3217        let new_cursor_position = newest_selection.head();
 3218        let selection_start = newest_selection.start;
 3219
 3220        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3221            self.push_to_nav_history(
 3222                *old_cursor_position,
 3223                Some(new_cursor_position.to_point(buffer)),
 3224                false,
 3225                effects.nav_history == Some(true),
 3226                cx,
 3227            );
 3228        }
 3229
 3230        if local {
 3231            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3232                self.register_buffer(buffer_id, cx);
 3233            }
 3234
 3235            let mut context_menu = self.context_menu.borrow_mut();
 3236            let completion_menu = match context_menu.as_ref() {
 3237                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3238                Some(CodeContextMenu::CodeActions(_)) => {
 3239                    *context_menu = None;
 3240                    None
 3241                }
 3242                None => None,
 3243            };
 3244            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3245            drop(context_menu);
 3246
 3247            if effects.completions
 3248                && let Some(completion_position) = completion_position
 3249            {
 3250                let start_offset = selection_start.to_offset(buffer);
 3251                let position_matches = start_offset == completion_position.to_offset(buffer);
 3252                let continue_showing = if position_matches {
 3253                    if self.snippet_stack.is_empty() {
 3254                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3255                            == Some(CharKind::Word)
 3256                    } else {
 3257                        // Snippet choices can be shown even when the cursor is in whitespace.
 3258                        // Dismissing the menu with actions like backspace is handled by
 3259                        // invalidation regions.
 3260                        true
 3261                    }
 3262                } else {
 3263                    false
 3264                };
 3265
 3266                if continue_showing {
 3267                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3268                } else {
 3269                    self.hide_context_menu(window, cx);
 3270                }
 3271            }
 3272
 3273            hide_hover(self, cx);
 3274
 3275            if old_cursor_position.to_display_point(&display_map).row()
 3276                != new_cursor_position.to_display_point(&display_map).row()
 3277            {
 3278                self.available_code_actions.take();
 3279            }
 3280            self.refresh_code_actions(window, cx);
 3281            self.refresh_document_highlights(cx);
 3282            refresh_linked_ranges(self, window, cx);
 3283
 3284            self.refresh_selected_text_highlights(false, window, cx);
 3285            self.refresh_matching_bracket_highlights(window, cx);
 3286            self.update_visible_edit_prediction(window, cx);
 3287            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3288            self.inline_blame_popover.take();
 3289            if self.git_blame_inline_enabled {
 3290                self.start_inline_blame_timer(window, cx);
 3291            }
 3292        }
 3293
 3294        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3295        cx.emit(EditorEvent::SelectionsChanged { local });
 3296
 3297        let selections = &self.selections.disjoint_anchors_arc();
 3298        if selections.len() == 1 {
 3299            cx.emit(SearchEvent::ActiveMatchChanged)
 3300        }
 3301        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3302            let inmemory_selections = selections
 3303                .iter()
 3304                .map(|s| {
 3305                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3306                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3307                })
 3308                .collect();
 3309            self.update_restoration_data(cx, |data| {
 3310                data.selections = inmemory_selections;
 3311            });
 3312
 3313            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3314                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3315            {
 3316                let snapshot = self.buffer().read(cx).snapshot(cx);
 3317                let selections = selections.clone();
 3318                let background_executor = cx.background_executor().clone();
 3319                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3320                self.serialize_selections = cx.background_spawn(async move {
 3321                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3322                    let db_selections = selections
 3323                        .iter()
 3324                        .map(|selection| {
 3325                            (
 3326                                selection.start.to_offset(&snapshot),
 3327                                selection.end.to_offset(&snapshot),
 3328                            )
 3329                        })
 3330                        .collect();
 3331
 3332                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3333                        .await
 3334                        .with_context(|| {
 3335                            format!(
 3336                                "persisting editor selections for editor {editor_id}, \
 3337                                workspace {workspace_id:?}"
 3338                            )
 3339                        })
 3340                        .log_err();
 3341                });
 3342            }
 3343        }
 3344
 3345        cx.notify();
 3346    }
 3347
 3348    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3349        use text::ToOffset as _;
 3350        use text::ToPoint as _;
 3351
 3352        if self.mode.is_minimap()
 3353            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3354        {
 3355            return;
 3356        }
 3357
 3358        if !self.buffer().read(cx).is_singleton() {
 3359            return;
 3360        }
 3361
 3362        let display_snapshot = self
 3363            .display_map
 3364            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3365        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3366            return;
 3367        };
 3368        let inmemory_folds = display_snapshot
 3369            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3370            .map(|fold| {
 3371                fold.range.start.text_anchor.to_point(&snapshot)
 3372                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3373            })
 3374            .collect();
 3375        self.update_restoration_data(cx, |data| {
 3376            data.folds = inmemory_folds;
 3377        });
 3378
 3379        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3380            return;
 3381        };
 3382        let background_executor = cx.background_executor().clone();
 3383        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3384        let db_folds = display_snapshot
 3385            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3386            .map(|fold| {
 3387                (
 3388                    fold.range.start.text_anchor.to_offset(&snapshot),
 3389                    fold.range.end.text_anchor.to_offset(&snapshot),
 3390                )
 3391            })
 3392            .collect();
 3393        self.serialize_folds = cx.background_spawn(async move {
 3394            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3395            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3396                .await
 3397                .with_context(|| {
 3398                    format!(
 3399                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3400                    )
 3401                })
 3402                .log_err();
 3403        });
 3404    }
 3405
 3406    pub fn sync_selections(
 3407        &mut self,
 3408        other: Entity<Editor>,
 3409        cx: &mut Context<Self>,
 3410    ) -> gpui::Subscription {
 3411        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3412        if !other_selections.is_empty() {
 3413            self.selections
 3414                .change_with(&self.display_snapshot(cx), |selections| {
 3415                    selections.select_anchors(other_selections);
 3416                });
 3417        }
 3418
 3419        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3420            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3421                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3422                if other_selections.is_empty() {
 3423                    return;
 3424                }
 3425                let snapshot = this.display_snapshot(cx);
 3426                this.selections.change_with(&snapshot, |selections| {
 3427                    selections.select_anchors(other_selections);
 3428                });
 3429            }
 3430        });
 3431
 3432        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3433            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3434                let these_selections = this.selections.disjoint_anchors().to_vec();
 3435                if these_selections.is_empty() {
 3436                    return;
 3437                }
 3438                other.update(cx, |other_editor, cx| {
 3439                    let snapshot = other_editor.display_snapshot(cx);
 3440                    other_editor
 3441                        .selections
 3442                        .change_with(&snapshot, |selections| {
 3443                            selections.select_anchors(these_selections);
 3444                        })
 3445                });
 3446            }
 3447        });
 3448
 3449        Subscription::join(other_subscription, this_subscription)
 3450    }
 3451
 3452    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3453        if self.buffer().read(cx).is_singleton() {
 3454            return;
 3455        }
 3456        let snapshot = self.buffer.read(cx).snapshot(cx);
 3457        let buffer_ids: HashSet<BufferId> = self
 3458            .selections
 3459            .disjoint_anchor_ranges()
 3460            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3461            .collect();
 3462        for buffer_id in buffer_ids {
 3463            self.unfold_buffer(buffer_id, cx);
 3464        }
 3465    }
 3466
 3467    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3468    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3469    /// effects of selection change occur at the end of the transaction.
 3470    pub fn change_selections<R>(
 3471        &mut self,
 3472        effects: SelectionEffects,
 3473        window: &mut Window,
 3474        cx: &mut Context<Self>,
 3475        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3476    ) -> R {
 3477        let snapshot = self.display_snapshot(cx);
 3478        if let Some(state) = &mut self.deferred_selection_effects_state {
 3479            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3480            state.effects.completions = effects.completions;
 3481            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3482            let (changed, result) = self.selections.change_with(&snapshot, change);
 3483            state.changed |= changed;
 3484            return result;
 3485        }
 3486        let mut state = DeferredSelectionEffectsState {
 3487            changed: false,
 3488            effects,
 3489            old_cursor_position: self.selections.newest_anchor().head(),
 3490            history_entry: SelectionHistoryEntry {
 3491                selections: self.selections.disjoint_anchors_arc(),
 3492                select_next_state: self.select_next_state.clone(),
 3493                select_prev_state: self.select_prev_state.clone(),
 3494                add_selections_state: self.add_selections_state.clone(),
 3495            },
 3496        };
 3497        let (changed, result) = self.selections.change_with(&snapshot, change);
 3498        state.changed = state.changed || changed;
 3499        if self.defer_selection_effects {
 3500            self.deferred_selection_effects_state = Some(state);
 3501        } else {
 3502            self.apply_selection_effects(state, window, cx);
 3503        }
 3504        result
 3505    }
 3506
 3507    /// Defers the effects of selection change, so that the effects of multiple calls to
 3508    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3509    /// to selection history and the state of popovers based on selection position aren't
 3510    /// erroneously updated.
 3511    pub fn with_selection_effects_deferred<R>(
 3512        &mut self,
 3513        window: &mut Window,
 3514        cx: &mut Context<Self>,
 3515        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3516    ) -> R {
 3517        let already_deferred = self.defer_selection_effects;
 3518        self.defer_selection_effects = true;
 3519        let result = update(self, window, cx);
 3520        if !already_deferred {
 3521            self.defer_selection_effects = false;
 3522            if let Some(state) = self.deferred_selection_effects_state.take() {
 3523                self.apply_selection_effects(state, window, cx);
 3524            }
 3525        }
 3526        result
 3527    }
 3528
 3529    fn apply_selection_effects(
 3530        &mut self,
 3531        state: DeferredSelectionEffectsState,
 3532        window: &mut Window,
 3533        cx: &mut Context<Self>,
 3534    ) {
 3535        if state.changed {
 3536            self.selection_history.push(state.history_entry);
 3537
 3538            if let Some(autoscroll) = state.effects.scroll {
 3539                self.request_autoscroll(autoscroll, cx);
 3540            }
 3541
 3542            let old_cursor_position = &state.old_cursor_position;
 3543
 3544            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3545
 3546            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3547                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3548            }
 3549        }
 3550    }
 3551
 3552    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3553    where
 3554        I: IntoIterator<Item = (Range<S>, T)>,
 3555        S: ToOffset,
 3556        T: Into<Arc<str>>,
 3557    {
 3558        if self.read_only(cx) {
 3559            return;
 3560        }
 3561
 3562        self.buffer
 3563            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3564    }
 3565
 3566    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3567    where
 3568        I: IntoIterator<Item = (Range<S>, T)>,
 3569        S: ToOffset,
 3570        T: Into<Arc<str>>,
 3571    {
 3572        if self.read_only(cx) {
 3573            return;
 3574        }
 3575
 3576        self.buffer.update(cx, |buffer, cx| {
 3577            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3578        });
 3579    }
 3580
 3581    pub fn edit_with_block_indent<I, S, T>(
 3582        &mut self,
 3583        edits: I,
 3584        original_indent_columns: Vec<Option<u32>>,
 3585        cx: &mut Context<Self>,
 3586    ) where
 3587        I: IntoIterator<Item = (Range<S>, T)>,
 3588        S: ToOffset,
 3589        T: Into<Arc<str>>,
 3590    {
 3591        if self.read_only(cx) {
 3592            return;
 3593        }
 3594
 3595        self.buffer.update(cx, |buffer, cx| {
 3596            buffer.edit(
 3597                edits,
 3598                Some(AutoindentMode::Block {
 3599                    original_indent_columns,
 3600                }),
 3601                cx,
 3602            )
 3603        });
 3604    }
 3605
 3606    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3607        self.hide_context_menu(window, cx);
 3608
 3609        match phase {
 3610            SelectPhase::Begin {
 3611                position,
 3612                add,
 3613                click_count,
 3614            } => self.begin_selection(position, add, click_count, window, cx),
 3615            SelectPhase::BeginColumnar {
 3616                position,
 3617                goal_column,
 3618                reset,
 3619                mode,
 3620            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3621            SelectPhase::Extend {
 3622                position,
 3623                click_count,
 3624            } => self.extend_selection(position, click_count, window, cx),
 3625            SelectPhase::Update {
 3626                position,
 3627                goal_column,
 3628                scroll_delta,
 3629            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3630            SelectPhase::End => self.end_selection(window, cx),
 3631        }
 3632    }
 3633
 3634    fn extend_selection(
 3635        &mut self,
 3636        position: DisplayPoint,
 3637        click_count: usize,
 3638        window: &mut Window,
 3639        cx: &mut Context<Self>,
 3640    ) {
 3641        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3642        let tail = self.selections.newest::<usize>(&display_map).tail();
 3643        let click_count = click_count.max(match self.selections.select_mode() {
 3644            SelectMode::Character => 1,
 3645            SelectMode::Word(_) => 2,
 3646            SelectMode::Line(_) => 3,
 3647            SelectMode::All => 4,
 3648        });
 3649        self.begin_selection(position, false, click_count, window, cx);
 3650
 3651        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3652
 3653        let current_selection = match self.selections.select_mode() {
 3654            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3655            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3656        };
 3657
 3658        let mut pending_selection = self
 3659            .selections
 3660            .pending_anchor()
 3661            .cloned()
 3662            .expect("extend_selection not called with pending selection");
 3663
 3664        if pending_selection
 3665            .start
 3666            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3667            == Ordering::Greater
 3668        {
 3669            pending_selection.start = current_selection.start;
 3670        }
 3671        if pending_selection
 3672            .end
 3673            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3674            == Ordering::Less
 3675        {
 3676            pending_selection.end = current_selection.end;
 3677            pending_selection.reversed = true;
 3678        }
 3679
 3680        let mut pending_mode = self.selections.pending_mode().unwrap();
 3681        match &mut pending_mode {
 3682            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3683            _ => {}
 3684        }
 3685
 3686        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3687            SelectionEffects::scroll(Autoscroll::fit())
 3688        } else {
 3689            SelectionEffects::no_scroll()
 3690        };
 3691
 3692        self.change_selections(effects, window, cx, |s| {
 3693            s.set_pending(pending_selection.clone(), pending_mode);
 3694            s.set_is_extending(true);
 3695        });
 3696    }
 3697
 3698    fn begin_selection(
 3699        &mut self,
 3700        position: DisplayPoint,
 3701        add: bool,
 3702        click_count: usize,
 3703        window: &mut Window,
 3704        cx: &mut Context<Self>,
 3705    ) {
 3706        if !self.focus_handle.is_focused(window) {
 3707            self.last_focused_descendant = None;
 3708            window.focus(&self.focus_handle);
 3709        }
 3710
 3711        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3712        let buffer = display_map.buffer_snapshot();
 3713        let position = display_map.clip_point(position, Bias::Left);
 3714
 3715        let start;
 3716        let end;
 3717        let mode;
 3718        let mut auto_scroll;
 3719        match click_count {
 3720            1 => {
 3721                start = buffer.anchor_before(position.to_point(&display_map));
 3722                end = start;
 3723                mode = SelectMode::Character;
 3724                auto_scroll = true;
 3725            }
 3726            2 => {
 3727                let position = display_map
 3728                    .clip_point(position, Bias::Left)
 3729                    .to_offset(&display_map, Bias::Left);
 3730                let (range, _) = buffer.surrounding_word(position, None);
 3731                start = buffer.anchor_before(range.start);
 3732                end = buffer.anchor_before(range.end);
 3733                mode = SelectMode::Word(start..end);
 3734                auto_scroll = true;
 3735            }
 3736            3 => {
 3737                let position = display_map
 3738                    .clip_point(position, Bias::Left)
 3739                    .to_point(&display_map);
 3740                let line_start = display_map.prev_line_boundary(position).0;
 3741                let next_line_start = buffer.clip_point(
 3742                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3743                    Bias::Left,
 3744                );
 3745                start = buffer.anchor_before(line_start);
 3746                end = buffer.anchor_before(next_line_start);
 3747                mode = SelectMode::Line(start..end);
 3748                auto_scroll = true;
 3749            }
 3750            _ => {
 3751                start = buffer.anchor_before(0);
 3752                end = buffer.anchor_before(buffer.len());
 3753                mode = SelectMode::All;
 3754                auto_scroll = false;
 3755            }
 3756        }
 3757        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3758
 3759        let point_to_delete: Option<usize> = {
 3760            let selected_points: Vec<Selection<Point>> =
 3761                self.selections.disjoint_in_range(start..end, &display_map);
 3762
 3763            if !add || click_count > 1 {
 3764                None
 3765            } else if !selected_points.is_empty() {
 3766                Some(selected_points[0].id)
 3767            } else {
 3768                let clicked_point_already_selected =
 3769                    self.selections.disjoint_anchors().iter().find(|selection| {
 3770                        selection.start.to_point(buffer) == start.to_point(buffer)
 3771                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3772                    });
 3773
 3774                clicked_point_already_selected.map(|selection| selection.id)
 3775            }
 3776        };
 3777
 3778        let selections_count = self.selections.count();
 3779        let effects = if auto_scroll {
 3780            SelectionEffects::default()
 3781        } else {
 3782            SelectionEffects::no_scroll()
 3783        };
 3784
 3785        self.change_selections(effects, window, cx, |s| {
 3786            if let Some(point_to_delete) = point_to_delete {
 3787                s.delete(point_to_delete);
 3788
 3789                if selections_count == 1 {
 3790                    s.set_pending_anchor_range(start..end, mode);
 3791                }
 3792            } else {
 3793                if !add {
 3794                    s.clear_disjoint();
 3795                }
 3796
 3797                s.set_pending_anchor_range(start..end, mode);
 3798            }
 3799        });
 3800    }
 3801
 3802    fn begin_columnar_selection(
 3803        &mut self,
 3804        position: DisplayPoint,
 3805        goal_column: u32,
 3806        reset: bool,
 3807        mode: ColumnarMode,
 3808        window: &mut Window,
 3809        cx: &mut Context<Self>,
 3810    ) {
 3811        if !self.focus_handle.is_focused(window) {
 3812            self.last_focused_descendant = None;
 3813            window.focus(&self.focus_handle);
 3814        }
 3815
 3816        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3817
 3818        if reset {
 3819            let pointer_position = display_map
 3820                .buffer_snapshot()
 3821                .anchor_before(position.to_point(&display_map));
 3822
 3823            self.change_selections(
 3824                SelectionEffects::scroll(Autoscroll::newest()),
 3825                window,
 3826                cx,
 3827                |s| {
 3828                    s.clear_disjoint();
 3829                    s.set_pending_anchor_range(
 3830                        pointer_position..pointer_position,
 3831                        SelectMode::Character,
 3832                    );
 3833                },
 3834            );
 3835        };
 3836
 3837        let tail = self.selections.newest::<Point>(&display_map).tail();
 3838        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3839        self.columnar_selection_state = match mode {
 3840            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3841                selection_tail: selection_anchor,
 3842                display_point: if reset {
 3843                    if position.column() != goal_column {
 3844                        Some(DisplayPoint::new(position.row(), goal_column))
 3845                    } else {
 3846                        None
 3847                    }
 3848                } else {
 3849                    None
 3850                },
 3851            }),
 3852            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3853                selection_tail: selection_anchor,
 3854            }),
 3855        };
 3856
 3857        if !reset {
 3858            self.select_columns(position, goal_column, &display_map, window, cx);
 3859        }
 3860    }
 3861
 3862    fn update_selection(
 3863        &mut self,
 3864        position: DisplayPoint,
 3865        goal_column: u32,
 3866        scroll_delta: gpui::Point<f32>,
 3867        window: &mut Window,
 3868        cx: &mut Context<Self>,
 3869    ) {
 3870        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3871
 3872        if self.columnar_selection_state.is_some() {
 3873            self.select_columns(position, goal_column, &display_map, window, cx);
 3874        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3875            let buffer = display_map.buffer_snapshot();
 3876            let head;
 3877            let tail;
 3878            let mode = self.selections.pending_mode().unwrap();
 3879            match &mode {
 3880                SelectMode::Character => {
 3881                    head = position.to_point(&display_map);
 3882                    tail = pending.tail().to_point(buffer);
 3883                }
 3884                SelectMode::Word(original_range) => {
 3885                    let offset = display_map
 3886                        .clip_point(position, Bias::Left)
 3887                        .to_offset(&display_map, Bias::Left);
 3888                    let original_range = original_range.to_offset(buffer);
 3889
 3890                    let head_offset = if buffer.is_inside_word(offset, None)
 3891                        || original_range.contains(&offset)
 3892                    {
 3893                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3894                        if word_range.start < original_range.start {
 3895                            word_range.start
 3896                        } else {
 3897                            word_range.end
 3898                        }
 3899                    } else {
 3900                        offset
 3901                    };
 3902
 3903                    head = head_offset.to_point(buffer);
 3904                    if head_offset <= original_range.start {
 3905                        tail = original_range.end.to_point(buffer);
 3906                    } else {
 3907                        tail = original_range.start.to_point(buffer);
 3908                    }
 3909                }
 3910                SelectMode::Line(original_range) => {
 3911                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3912
 3913                    let position = display_map
 3914                        .clip_point(position, Bias::Left)
 3915                        .to_point(&display_map);
 3916                    let line_start = display_map.prev_line_boundary(position).0;
 3917                    let next_line_start = buffer.clip_point(
 3918                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3919                        Bias::Left,
 3920                    );
 3921
 3922                    if line_start < original_range.start {
 3923                        head = line_start
 3924                    } else {
 3925                        head = next_line_start
 3926                    }
 3927
 3928                    if head <= original_range.start {
 3929                        tail = original_range.end;
 3930                    } else {
 3931                        tail = original_range.start;
 3932                    }
 3933                }
 3934                SelectMode::All => {
 3935                    return;
 3936                }
 3937            };
 3938
 3939            if head < tail {
 3940                pending.start = buffer.anchor_before(head);
 3941                pending.end = buffer.anchor_before(tail);
 3942                pending.reversed = true;
 3943            } else {
 3944                pending.start = buffer.anchor_before(tail);
 3945                pending.end = buffer.anchor_before(head);
 3946                pending.reversed = false;
 3947            }
 3948
 3949            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3950                s.set_pending(pending.clone(), mode);
 3951            });
 3952        } else {
 3953            log::error!("update_selection dispatched with no pending selection");
 3954            return;
 3955        }
 3956
 3957        self.apply_scroll_delta(scroll_delta, window, cx);
 3958        cx.notify();
 3959    }
 3960
 3961    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3962        self.columnar_selection_state.take();
 3963        if let Some(pending_mode) = self.selections.pending_mode() {
 3964            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3965            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3966                s.select(selections);
 3967                s.clear_pending();
 3968                if s.is_extending() {
 3969                    s.set_is_extending(false);
 3970                } else {
 3971                    s.set_select_mode(pending_mode);
 3972                }
 3973            });
 3974        }
 3975    }
 3976
 3977    fn select_columns(
 3978        &mut self,
 3979        head: DisplayPoint,
 3980        goal_column: u32,
 3981        display_map: &DisplaySnapshot,
 3982        window: &mut Window,
 3983        cx: &mut Context<Self>,
 3984    ) {
 3985        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3986            return;
 3987        };
 3988
 3989        let tail = match columnar_state {
 3990            ColumnarSelectionState::FromMouse {
 3991                selection_tail,
 3992                display_point,
 3993            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3994            ColumnarSelectionState::FromSelection { selection_tail } => {
 3995                selection_tail.to_display_point(display_map)
 3996            }
 3997        };
 3998
 3999        let start_row = cmp::min(tail.row(), head.row());
 4000        let end_row = cmp::max(tail.row(), head.row());
 4001        let start_column = cmp::min(tail.column(), goal_column);
 4002        let end_column = cmp::max(tail.column(), goal_column);
 4003        let reversed = start_column < tail.column();
 4004
 4005        let selection_ranges = (start_row.0..=end_row.0)
 4006            .map(DisplayRow)
 4007            .filter_map(|row| {
 4008                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4009                    || start_column <= display_map.line_len(row))
 4010                    && !display_map.is_block_line(row)
 4011                {
 4012                    let start = display_map
 4013                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4014                        .to_point(display_map);
 4015                    let end = display_map
 4016                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4017                        .to_point(display_map);
 4018                    if reversed {
 4019                        Some(end..start)
 4020                    } else {
 4021                        Some(start..end)
 4022                    }
 4023                } else {
 4024                    None
 4025                }
 4026            })
 4027            .collect::<Vec<_>>();
 4028        if selection_ranges.is_empty() {
 4029            return;
 4030        }
 4031
 4032        let ranges = match columnar_state {
 4033            ColumnarSelectionState::FromMouse { .. } => {
 4034                let mut non_empty_ranges = selection_ranges
 4035                    .iter()
 4036                    .filter(|selection_range| selection_range.start != selection_range.end)
 4037                    .peekable();
 4038                if non_empty_ranges.peek().is_some() {
 4039                    non_empty_ranges.cloned().collect()
 4040                } else {
 4041                    selection_ranges
 4042                }
 4043            }
 4044            _ => selection_ranges,
 4045        };
 4046
 4047        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4048            s.select_ranges(ranges);
 4049        });
 4050        cx.notify();
 4051    }
 4052
 4053    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4054        self.selections
 4055            .all_adjusted(snapshot)
 4056            .iter()
 4057            .any(|selection| !selection.is_empty())
 4058    }
 4059
 4060    pub fn has_pending_nonempty_selection(&self) -> bool {
 4061        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4062            Some(Selection { start, end, .. }) => start != end,
 4063            None => false,
 4064        };
 4065
 4066        pending_nonempty_selection
 4067            || (self.columnar_selection_state.is_some()
 4068                && self.selections.disjoint_anchors().len() > 1)
 4069    }
 4070
 4071    pub fn has_pending_selection(&self) -> bool {
 4072        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4073    }
 4074
 4075    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4076        self.selection_mark_mode = false;
 4077        self.selection_drag_state = SelectionDragState::None;
 4078
 4079        if self.dismiss_menus_and_popups(true, window, cx) {
 4080            cx.notify();
 4081            return;
 4082        }
 4083        if self.clear_expanded_diff_hunks(cx) {
 4084            cx.notify();
 4085            return;
 4086        }
 4087        if self.show_git_blame_gutter {
 4088            self.show_git_blame_gutter = false;
 4089            cx.notify();
 4090            return;
 4091        }
 4092
 4093        if self.mode.is_full()
 4094            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4095        {
 4096            cx.notify();
 4097            return;
 4098        }
 4099
 4100        cx.propagate();
 4101    }
 4102
 4103    pub fn dismiss_menus_and_popups(
 4104        &mut self,
 4105        is_user_requested: bool,
 4106        window: &mut Window,
 4107        cx: &mut Context<Self>,
 4108    ) -> bool {
 4109        if self.take_rename(false, window, cx).is_some() {
 4110            return true;
 4111        }
 4112
 4113        if self.hide_blame_popover(true, cx) {
 4114            return true;
 4115        }
 4116
 4117        if hide_hover(self, cx) {
 4118            return true;
 4119        }
 4120
 4121        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4122            return true;
 4123        }
 4124
 4125        if self.hide_context_menu(window, cx).is_some() {
 4126            return true;
 4127        }
 4128
 4129        if self.mouse_context_menu.take().is_some() {
 4130            return true;
 4131        }
 4132
 4133        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4134            return true;
 4135        }
 4136
 4137        if self.snippet_stack.pop().is_some() {
 4138            return true;
 4139        }
 4140
 4141        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4142            self.dismiss_diagnostics(cx);
 4143            return true;
 4144        }
 4145
 4146        false
 4147    }
 4148
 4149    fn linked_editing_ranges_for(
 4150        &self,
 4151        selection: Range<text::Anchor>,
 4152        cx: &App,
 4153    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4154        if self.linked_edit_ranges.is_empty() {
 4155            return None;
 4156        }
 4157        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4158            selection.end.buffer_id.and_then(|end_buffer_id| {
 4159                if selection.start.buffer_id != Some(end_buffer_id) {
 4160                    return None;
 4161                }
 4162                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4163                let snapshot = buffer.read(cx).snapshot();
 4164                self.linked_edit_ranges
 4165                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4166                    .map(|ranges| (ranges, snapshot, buffer))
 4167            })?;
 4168        use text::ToOffset as TO;
 4169        // find offset from the start of current range to current cursor position
 4170        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4171
 4172        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4173        let start_difference = start_offset - start_byte_offset;
 4174        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4175        let end_difference = end_offset - start_byte_offset;
 4176        // Current range has associated linked ranges.
 4177        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4178        for range in linked_ranges.iter() {
 4179            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4180            let end_offset = start_offset + end_difference;
 4181            let start_offset = start_offset + start_difference;
 4182            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4183                continue;
 4184            }
 4185            if self.selections.disjoint_anchor_ranges().any(|s| {
 4186                if s.start.buffer_id != selection.start.buffer_id
 4187                    || s.end.buffer_id != selection.end.buffer_id
 4188                {
 4189                    return false;
 4190                }
 4191                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4192                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4193            }) {
 4194                continue;
 4195            }
 4196            let start = buffer_snapshot.anchor_after(start_offset);
 4197            let end = buffer_snapshot.anchor_after(end_offset);
 4198            linked_edits
 4199                .entry(buffer.clone())
 4200                .or_default()
 4201                .push(start..end);
 4202        }
 4203        Some(linked_edits)
 4204    }
 4205
 4206    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4207        let text: Arc<str> = text.into();
 4208
 4209        if self.read_only(cx) {
 4210            return;
 4211        }
 4212
 4213        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4214
 4215        self.unfold_buffers_with_selections(cx);
 4216
 4217        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4218        let mut bracket_inserted = false;
 4219        let mut edits = Vec::new();
 4220        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4221        let mut new_selections = Vec::with_capacity(selections.len());
 4222        let mut new_autoclose_regions = Vec::new();
 4223        let snapshot = self.buffer.read(cx).read(cx);
 4224        let mut clear_linked_edit_ranges = false;
 4225
 4226        for (selection, autoclose_region) in
 4227            self.selections_with_autoclose_regions(selections, &snapshot)
 4228        {
 4229            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4230                // Determine if the inserted text matches the opening or closing
 4231                // bracket of any of this language's bracket pairs.
 4232                let mut bracket_pair = None;
 4233                let mut is_bracket_pair_start = false;
 4234                let mut is_bracket_pair_end = false;
 4235                if !text.is_empty() {
 4236                    let mut bracket_pair_matching_end = None;
 4237                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4238                    //  and they are removing the character that triggered IME popup.
 4239                    for (pair, enabled) in scope.brackets() {
 4240                        if !pair.close && !pair.surround {
 4241                            continue;
 4242                        }
 4243
 4244                        if enabled && pair.start.ends_with(text.as_ref()) {
 4245                            let prefix_len = pair.start.len() - text.len();
 4246                            let preceding_text_matches_prefix = prefix_len == 0
 4247                                || (selection.start.column >= (prefix_len as u32)
 4248                                    && snapshot.contains_str_at(
 4249                                        Point::new(
 4250                                            selection.start.row,
 4251                                            selection.start.column - (prefix_len as u32),
 4252                                        ),
 4253                                        &pair.start[..prefix_len],
 4254                                    ));
 4255                            if preceding_text_matches_prefix {
 4256                                bracket_pair = Some(pair.clone());
 4257                                is_bracket_pair_start = true;
 4258                                break;
 4259                            }
 4260                        }
 4261                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4262                        {
 4263                            // take first bracket pair matching end, but don't break in case a later bracket
 4264                            // pair matches start
 4265                            bracket_pair_matching_end = Some(pair.clone());
 4266                        }
 4267                    }
 4268                    if let Some(end) = bracket_pair_matching_end
 4269                        && bracket_pair.is_none()
 4270                    {
 4271                        bracket_pair = Some(end);
 4272                        is_bracket_pair_end = true;
 4273                    }
 4274                }
 4275
 4276                if let Some(bracket_pair) = bracket_pair {
 4277                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4278                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4279                    let auto_surround =
 4280                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4281                    if selection.is_empty() {
 4282                        if is_bracket_pair_start {
 4283                            // If the inserted text is a suffix of an opening bracket and the
 4284                            // selection is preceded by the rest of the opening bracket, then
 4285                            // insert the closing bracket.
 4286                            let following_text_allows_autoclose = snapshot
 4287                                .chars_at(selection.start)
 4288                                .next()
 4289                                .is_none_or(|c| scope.should_autoclose_before(c));
 4290
 4291                            let preceding_text_allows_autoclose = selection.start.column == 0
 4292                                || snapshot
 4293                                    .reversed_chars_at(selection.start)
 4294                                    .next()
 4295                                    .is_none_or(|c| {
 4296                                        bracket_pair.start != bracket_pair.end
 4297                                            || !snapshot
 4298                                                .char_classifier_at(selection.start)
 4299                                                .is_word(c)
 4300                                    });
 4301
 4302                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4303                                && bracket_pair.start.len() == 1
 4304                            {
 4305                                let target = bracket_pair.start.chars().next().unwrap();
 4306                                let current_line_count = snapshot
 4307                                    .reversed_chars_at(selection.start)
 4308                                    .take_while(|&c| c != '\n')
 4309                                    .filter(|&c| c == target)
 4310                                    .count();
 4311                                current_line_count % 2 == 1
 4312                            } else {
 4313                                false
 4314                            };
 4315
 4316                            if autoclose
 4317                                && bracket_pair.close
 4318                                && following_text_allows_autoclose
 4319                                && preceding_text_allows_autoclose
 4320                                && !is_closing_quote
 4321                            {
 4322                                let anchor = snapshot.anchor_before(selection.end);
 4323                                new_selections.push((selection.map(|_| anchor), text.len()));
 4324                                new_autoclose_regions.push((
 4325                                    anchor,
 4326                                    text.len(),
 4327                                    selection.id,
 4328                                    bracket_pair.clone(),
 4329                                ));
 4330                                edits.push((
 4331                                    selection.range(),
 4332                                    format!("{}{}", text, bracket_pair.end).into(),
 4333                                ));
 4334                                bracket_inserted = true;
 4335                                continue;
 4336                            }
 4337                        }
 4338
 4339                        if let Some(region) = autoclose_region {
 4340                            // If the selection is followed by an auto-inserted closing bracket,
 4341                            // then don't insert that closing bracket again; just move the selection
 4342                            // past the closing bracket.
 4343                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4344                                && text.as_ref() == region.pair.end.as_str()
 4345                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4346                            if should_skip {
 4347                                let anchor = snapshot.anchor_after(selection.end);
 4348                                new_selections
 4349                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4350                                continue;
 4351                            }
 4352                        }
 4353
 4354                        let always_treat_brackets_as_autoclosed = snapshot
 4355                            .language_settings_at(selection.start, cx)
 4356                            .always_treat_brackets_as_autoclosed;
 4357                        if always_treat_brackets_as_autoclosed
 4358                            && is_bracket_pair_end
 4359                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4360                        {
 4361                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4362                            // and the inserted text is a closing bracket and the selection is followed
 4363                            // by the closing bracket then move the selection past the closing bracket.
 4364                            let anchor = snapshot.anchor_after(selection.end);
 4365                            new_selections.push((selection.map(|_| anchor), text.len()));
 4366                            continue;
 4367                        }
 4368                    }
 4369                    // If an opening bracket is 1 character long and is typed while
 4370                    // text is selected, then surround that text with the bracket pair.
 4371                    else if auto_surround
 4372                        && bracket_pair.surround
 4373                        && is_bracket_pair_start
 4374                        && bracket_pair.start.chars().count() == 1
 4375                    {
 4376                        edits.push((selection.start..selection.start, text.clone()));
 4377                        edits.push((
 4378                            selection.end..selection.end,
 4379                            bracket_pair.end.as_str().into(),
 4380                        ));
 4381                        bracket_inserted = true;
 4382                        new_selections.push((
 4383                            Selection {
 4384                                id: selection.id,
 4385                                start: snapshot.anchor_after(selection.start),
 4386                                end: snapshot.anchor_before(selection.end),
 4387                                reversed: selection.reversed,
 4388                                goal: selection.goal,
 4389                            },
 4390                            0,
 4391                        ));
 4392                        continue;
 4393                    }
 4394                }
 4395            }
 4396
 4397            if self.auto_replace_emoji_shortcode
 4398                && selection.is_empty()
 4399                && text.as_ref().ends_with(':')
 4400                && let Some(possible_emoji_short_code) =
 4401                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4402                && !possible_emoji_short_code.is_empty()
 4403                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4404            {
 4405                let emoji_shortcode_start = Point::new(
 4406                    selection.start.row,
 4407                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4408                );
 4409
 4410                // Remove shortcode from buffer
 4411                edits.push((
 4412                    emoji_shortcode_start..selection.start,
 4413                    "".to_string().into(),
 4414                ));
 4415                new_selections.push((
 4416                    Selection {
 4417                        id: selection.id,
 4418                        start: snapshot.anchor_after(emoji_shortcode_start),
 4419                        end: snapshot.anchor_before(selection.start),
 4420                        reversed: selection.reversed,
 4421                        goal: selection.goal,
 4422                    },
 4423                    0,
 4424                ));
 4425
 4426                // Insert emoji
 4427                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4428                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4429                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4430
 4431                continue;
 4432            }
 4433
 4434            // If not handling any auto-close operation, then just replace the selected
 4435            // text with the given input and move the selection to the end of the
 4436            // newly inserted text.
 4437            let anchor = snapshot.anchor_after(selection.end);
 4438            if !self.linked_edit_ranges.is_empty() {
 4439                let start_anchor = snapshot.anchor_before(selection.start);
 4440
 4441                let is_word_char = text.chars().next().is_none_or(|char| {
 4442                    let classifier = snapshot
 4443                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4444                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4445                    classifier.is_word(char)
 4446                });
 4447
 4448                if is_word_char {
 4449                    if let Some(ranges) = self
 4450                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4451                    {
 4452                        for (buffer, edits) in ranges {
 4453                            linked_edits
 4454                                .entry(buffer.clone())
 4455                                .or_default()
 4456                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4457                        }
 4458                    }
 4459                } else {
 4460                    clear_linked_edit_ranges = true;
 4461                }
 4462            }
 4463
 4464            new_selections.push((selection.map(|_| anchor), 0));
 4465            edits.push((selection.start..selection.end, text.clone()));
 4466        }
 4467
 4468        drop(snapshot);
 4469
 4470        self.transact(window, cx, |this, window, cx| {
 4471            if clear_linked_edit_ranges {
 4472                this.linked_edit_ranges.clear();
 4473            }
 4474            let initial_buffer_versions =
 4475                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4476
 4477            this.buffer.update(cx, |buffer, cx| {
 4478                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4479            });
 4480            for (buffer, edits) in linked_edits {
 4481                buffer.update(cx, |buffer, cx| {
 4482                    let snapshot = buffer.snapshot();
 4483                    let edits = edits
 4484                        .into_iter()
 4485                        .map(|(range, text)| {
 4486                            use text::ToPoint as TP;
 4487                            let end_point = TP::to_point(&range.end, &snapshot);
 4488                            let start_point = TP::to_point(&range.start, &snapshot);
 4489                            (start_point..end_point, text)
 4490                        })
 4491                        .sorted_by_key(|(range, _)| range.start);
 4492                    buffer.edit(edits, None, cx);
 4493                })
 4494            }
 4495            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4496            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4497            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4498            let new_selections =
 4499                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4500                    .zip(new_selection_deltas)
 4501                    .map(|(selection, delta)| Selection {
 4502                        id: selection.id,
 4503                        start: selection.start + delta,
 4504                        end: selection.end + delta,
 4505                        reversed: selection.reversed,
 4506                        goal: SelectionGoal::None,
 4507                    })
 4508                    .collect::<Vec<_>>();
 4509
 4510            let mut i = 0;
 4511            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4512                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4513                let start = map.buffer_snapshot().anchor_before(position);
 4514                let end = map.buffer_snapshot().anchor_after(position);
 4515                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4516                    match existing_state
 4517                        .range
 4518                        .start
 4519                        .cmp(&start, map.buffer_snapshot())
 4520                    {
 4521                        Ordering::Less => i += 1,
 4522                        Ordering::Greater => break,
 4523                        Ordering::Equal => {
 4524                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4525                                Ordering::Less => i += 1,
 4526                                Ordering::Equal => break,
 4527                                Ordering::Greater => break,
 4528                            }
 4529                        }
 4530                    }
 4531                }
 4532                this.autoclose_regions.insert(
 4533                    i,
 4534                    AutocloseRegion {
 4535                        selection_id,
 4536                        range: start..end,
 4537                        pair,
 4538                    },
 4539                );
 4540            }
 4541
 4542            let had_active_edit_prediction = this.has_active_edit_prediction();
 4543            this.change_selections(
 4544                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4545                window,
 4546                cx,
 4547                |s| s.select(new_selections),
 4548            );
 4549
 4550            if !bracket_inserted
 4551                && let Some(on_type_format_task) =
 4552                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4553            {
 4554                on_type_format_task.detach_and_log_err(cx);
 4555            }
 4556
 4557            let editor_settings = EditorSettings::get_global(cx);
 4558            if bracket_inserted
 4559                && (editor_settings.auto_signature_help
 4560                    || editor_settings.show_signature_help_after_edits)
 4561            {
 4562                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4563            }
 4564
 4565            let trigger_in_words =
 4566                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4567            if this.hard_wrap.is_some() {
 4568                let latest: Range<Point> = this.selections.newest(&map).range();
 4569                if latest.is_empty()
 4570                    && this
 4571                        .buffer()
 4572                        .read(cx)
 4573                        .snapshot(cx)
 4574                        .line_len(MultiBufferRow(latest.start.row))
 4575                        == latest.start.column
 4576                {
 4577                    this.rewrap_impl(
 4578                        RewrapOptions {
 4579                            override_language_settings: true,
 4580                            preserve_existing_whitespace: true,
 4581                        },
 4582                        cx,
 4583                    )
 4584                }
 4585            }
 4586            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4587            refresh_linked_ranges(this, window, cx);
 4588            this.refresh_edit_prediction(true, false, window, cx);
 4589            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4590        });
 4591    }
 4592
 4593    fn find_possible_emoji_shortcode_at_position(
 4594        snapshot: &MultiBufferSnapshot,
 4595        position: Point,
 4596    ) -> Option<String> {
 4597        let mut chars = Vec::new();
 4598        let mut found_colon = false;
 4599        for char in snapshot.reversed_chars_at(position).take(100) {
 4600            // Found a possible emoji shortcode in the middle of the buffer
 4601            if found_colon {
 4602                if char.is_whitespace() {
 4603                    chars.reverse();
 4604                    return Some(chars.iter().collect());
 4605                }
 4606                // If the previous character is not a whitespace, we are in the middle of a word
 4607                // and we only want to complete the shortcode if the word is made up of other emojis
 4608                let mut containing_word = String::new();
 4609                for ch in snapshot
 4610                    .reversed_chars_at(position)
 4611                    .skip(chars.len() + 1)
 4612                    .take(100)
 4613                {
 4614                    if ch.is_whitespace() {
 4615                        break;
 4616                    }
 4617                    containing_word.push(ch);
 4618                }
 4619                let containing_word = containing_word.chars().rev().collect::<String>();
 4620                if util::word_consists_of_emojis(containing_word.as_str()) {
 4621                    chars.reverse();
 4622                    return Some(chars.iter().collect());
 4623                }
 4624            }
 4625
 4626            if char.is_whitespace() || !char.is_ascii() {
 4627                return None;
 4628            }
 4629            if char == ':' {
 4630                found_colon = true;
 4631            } else {
 4632                chars.push(char);
 4633            }
 4634        }
 4635        // Found a possible emoji shortcode at the beginning of the buffer
 4636        chars.reverse();
 4637        Some(chars.iter().collect())
 4638    }
 4639
 4640    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4641        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4642        self.transact(window, cx, |this, window, cx| {
 4643            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4644                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4645                let multi_buffer = this.buffer.read(cx);
 4646                let buffer = multi_buffer.snapshot(cx);
 4647                selections
 4648                    .iter()
 4649                    .map(|selection| {
 4650                        let start_point = selection.start.to_point(&buffer);
 4651                        let mut existing_indent =
 4652                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4653                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4654                        let start = selection.start;
 4655                        let end = selection.end;
 4656                        let selection_is_empty = start == end;
 4657                        let language_scope = buffer.language_scope_at(start);
 4658                        let (
 4659                            comment_delimiter,
 4660                            doc_delimiter,
 4661                            insert_extra_newline,
 4662                            indent_on_newline,
 4663                            indent_on_extra_newline,
 4664                        ) = if let Some(language) = &language_scope {
 4665                            let mut insert_extra_newline =
 4666                                insert_extra_newline_brackets(&buffer, start..end, language)
 4667                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4668
 4669                            // Comment extension on newline is allowed only for cursor selections
 4670                            let comment_delimiter = maybe!({
 4671                                if !selection_is_empty {
 4672                                    return None;
 4673                                }
 4674
 4675                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4676                                    return None;
 4677                                }
 4678
 4679                                let delimiters = language.line_comment_prefixes();
 4680                                let max_len_of_delimiter =
 4681                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4682                                let (snapshot, range) =
 4683                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4684
 4685                                let num_of_whitespaces = snapshot
 4686                                    .chars_for_range(range.clone())
 4687                                    .take_while(|c| c.is_whitespace())
 4688                                    .count();
 4689                                let comment_candidate = snapshot
 4690                                    .chars_for_range(range.clone())
 4691                                    .skip(num_of_whitespaces)
 4692                                    .take(max_len_of_delimiter)
 4693                                    .collect::<String>();
 4694                                let (delimiter, trimmed_len) = delimiters
 4695                                    .iter()
 4696                                    .filter_map(|delimiter| {
 4697                                        let prefix = delimiter.trim_end();
 4698                                        if comment_candidate.starts_with(prefix) {
 4699                                            Some((delimiter, prefix.len()))
 4700                                        } else {
 4701                                            None
 4702                                        }
 4703                                    })
 4704                                    .max_by_key(|(_, len)| *len)?;
 4705
 4706                                if let Some(BlockCommentConfig {
 4707                                    start: block_start, ..
 4708                                }) = language.block_comment()
 4709                                {
 4710                                    let block_start_trimmed = block_start.trim_end();
 4711                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4712                                        let line_content = snapshot
 4713                                            .chars_for_range(range)
 4714                                            .skip(num_of_whitespaces)
 4715                                            .take(block_start_trimmed.len())
 4716                                            .collect::<String>();
 4717
 4718                                        if line_content.starts_with(block_start_trimmed) {
 4719                                            return None;
 4720                                        }
 4721                                    }
 4722                                }
 4723
 4724                                let cursor_is_placed_after_comment_marker =
 4725                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4726                                if cursor_is_placed_after_comment_marker {
 4727                                    Some(delimiter.clone())
 4728                                } else {
 4729                                    None
 4730                                }
 4731                            });
 4732
 4733                            let mut indent_on_newline = IndentSize::spaces(0);
 4734                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4735
 4736                            let doc_delimiter = maybe!({
 4737                                if !selection_is_empty {
 4738                                    return None;
 4739                                }
 4740
 4741                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4742                                    return None;
 4743                                }
 4744
 4745                                let BlockCommentConfig {
 4746                                    start: start_tag,
 4747                                    end: end_tag,
 4748                                    prefix: delimiter,
 4749                                    tab_size: len,
 4750                                } = language.documentation_comment()?;
 4751                                let is_within_block_comment = buffer
 4752                                    .language_scope_at(start_point)
 4753                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4754                                if !is_within_block_comment {
 4755                                    return None;
 4756                                }
 4757
 4758                                let (snapshot, range) =
 4759                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4760
 4761                                let num_of_whitespaces = snapshot
 4762                                    .chars_for_range(range.clone())
 4763                                    .take_while(|c| c.is_whitespace())
 4764                                    .count();
 4765
 4766                                // 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.
 4767                                let column = start_point.column;
 4768                                let cursor_is_after_start_tag = {
 4769                                    let start_tag_len = start_tag.len();
 4770                                    let start_tag_line = snapshot
 4771                                        .chars_for_range(range.clone())
 4772                                        .skip(num_of_whitespaces)
 4773                                        .take(start_tag_len)
 4774                                        .collect::<String>();
 4775                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4776                                        num_of_whitespaces + start_tag_len <= column as usize
 4777                                    } else {
 4778                                        false
 4779                                    }
 4780                                };
 4781
 4782                                let cursor_is_after_delimiter = {
 4783                                    let delimiter_trim = delimiter.trim_end();
 4784                                    let delimiter_line = snapshot
 4785                                        .chars_for_range(range.clone())
 4786                                        .skip(num_of_whitespaces)
 4787                                        .take(delimiter_trim.len())
 4788                                        .collect::<String>();
 4789                                    if delimiter_line.starts_with(delimiter_trim) {
 4790                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4791                                    } else {
 4792                                        false
 4793                                    }
 4794                                };
 4795
 4796                                let cursor_is_before_end_tag_if_exists = {
 4797                                    let mut char_position = 0u32;
 4798                                    let mut end_tag_offset = None;
 4799
 4800                                    'outer: for chunk in snapshot.text_for_range(range) {
 4801                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4802                                            let chars_before_match =
 4803                                                chunk[..byte_pos].chars().count() as u32;
 4804                                            end_tag_offset =
 4805                                                Some(char_position + chars_before_match);
 4806                                            break 'outer;
 4807                                        }
 4808                                        char_position += chunk.chars().count() as u32;
 4809                                    }
 4810
 4811                                    if let Some(end_tag_offset) = end_tag_offset {
 4812                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4813                                        if cursor_is_after_start_tag {
 4814                                            if cursor_is_before_end_tag {
 4815                                                insert_extra_newline = true;
 4816                                            }
 4817                                            let cursor_is_at_start_of_end_tag =
 4818                                                column == end_tag_offset;
 4819                                            if cursor_is_at_start_of_end_tag {
 4820                                                indent_on_extra_newline.len = *len;
 4821                                            }
 4822                                        }
 4823                                        cursor_is_before_end_tag
 4824                                    } else {
 4825                                        true
 4826                                    }
 4827                                };
 4828
 4829                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4830                                    && cursor_is_before_end_tag_if_exists
 4831                                {
 4832                                    if cursor_is_after_start_tag {
 4833                                        indent_on_newline.len = *len;
 4834                                    }
 4835                                    Some(delimiter.clone())
 4836                                } else {
 4837                                    None
 4838                                }
 4839                            });
 4840
 4841                            (
 4842                                comment_delimiter,
 4843                                doc_delimiter,
 4844                                insert_extra_newline,
 4845                                indent_on_newline,
 4846                                indent_on_extra_newline,
 4847                            )
 4848                        } else {
 4849                            (
 4850                                None,
 4851                                None,
 4852                                false,
 4853                                IndentSize::default(),
 4854                                IndentSize::default(),
 4855                            )
 4856                        };
 4857
 4858                        let prevent_auto_indent = doc_delimiter.is_some();
 4859                        let delimiter = comment_delimiter.or(doc_delimiter);
 4860
 4861                        let capacity_for_delimiter =
 4862                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4863                        let mut new_text = String::with_capacity(
 4864                            1 + capacity_for_delimiter
 4865                                + existing_indent.len as usize
 4866                                + indent_on_newline.len as usize
 4867                                + indent_on_extra_newline.len as usize,
 4868                        );
 4869                        new_text.push('\n');
 4870                        new_text.extend(existing_indent.chars());
 4871                        new_text.extend(indent_on_newline.chars());
 4872
 4873                        if let Some(delimiter) = &delimiter {
 4874                            new_text.push_str(delimiter);
 4875                        }
 4876
 4877                        if insert_extra_newline {
 4878                            new_text.push('\n');
 4879                            new_text.extend(existing_indent.chars());
 4880                            new_text.extend(indent_on_extra_newline.chars());
 4881                        }
 4882
 4883                        let anchor = buffer.anchor_after(end);
 4884                        let new_selection = selection.map(|_| anchor);
 4885                        (
 4886                            ((start..end, new_text), prevent_auto_indent),
 4887                            (insert_extra_newline, new_selection),
 4888                        )
 4889                    })
 4890                    .unzip()
 4891            };
 4892
 4893            let mut auto_indent_edits = Vec::new();
 4894            let mut edits = Vec::new();
 4895            for (edit, prevent_auto_indent) in edits_with_flags {
 4896                if prevent_auto_indent {
 4897                    edits.push(edit);
 4898                } else {
 4899                    auto_indent_edits.push(edit);
 4900                }
 4901            }
 4902            if !edits.is_empty() {
 4903                this.edit(edits, cx);
 4904            }
 4905            if !auto_indent_edits.is_empty() {
 4906                this.edit_with_autoindent(auto_indent_edits, cx);
 4907            }
 4908
 4909            let buffer = this.buffer.read(cx).snapshot(cx);
 4910            let new_selections = selection_info
 4911                .into_iter()
 4912                .map(|(extra_newline_inserted, new_selection)| {
 4913                    let mut cursor = new_selection.end.to_point(&buffer);
 4914                    if extra_newline_inserted {
 4915                        cursor.row -= 1;
 4916                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4917                    }
 4918                    new_selection.map(|_| cursor)
 4919                })
 4920                .collect();
 4921
 4922            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4923            this.refresh_edit_prediction(true, false, window, cx);
 4924        });
 4925    }
 4926
 4927    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4928        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4929
 4930        let buffer = self.buffer.read(cx);
 4931        let snapshot = buffer.snapshot(cx);
 4932
 4933        let mut edits = Vec::new();
 4934        let mut rows = Vec::new();
 4935
 4936        for (rows_inserted, selection) in self
 4937            .selections
 4938            .all_adjusted(&self.display_snapshot(cx))
 4939            .into_iter()
 4940            .enumerate()
 4941        {
 4942            let cursor = selection.head();
 4943            let row = cursor.row;
 4944
 4945            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4946
 4947            let newline = "\n".to_string();
 4948            edits.push((start_of_line..start_of_line, newline));
 4949
 4950            rows.push(row + rows_inserted as u32);
 4951        }
 4952
 4953        self.transact(window, cx, |editor, window, cx| {
 4954            editor.edit(edits, cx);
 4955
 4956            editor.change_selections(Default::default(), window, cx, |s| {
 4957                let mut index = 0;
 4958                s.move_cursors_with(|map, _, _| {
 4959                    let row = rows[index];
 4960                    index += 1;
 4961
 4962                    let point = Point::new(row, 0);
 4963                    let boundary = map.next_line_boundary(point).1;
 4964                    let clipped = map.clip_point(boundary, Bias::Left);
 4965
 4966                    (clipped, SelectionGoal::None)
 4967                });
 4968            });
 4969
 4970            let mut indent_edits = Vec::new();
 4971            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4972            for row in rows {
 4973                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4974                for (row, indent) in indents {
 4975                    if indent.len == 0 {
 4976                        continue;
 4977                    }
 4978
 4979                    let text = match indent.kind {
 4980                        IndentKind::Space => " ".repeat(indent.len as usize),
 4981                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4982                    };
 4983                    let point = Point::new(row.0, 0);
 4984                    indent_edits.push((point..point, text));
 4985                }
 4986            }
 4987            editor.edit(indent_edits, cx);
 4988        });
 4989    }
 4990
 4991    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4992        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4993
 4994        let buffer = self.buffer.read(cx);
 4995        let snapshot = buffer.snapshot(cx);
 4996
 4997        let mut edits = Vec::new();
 4998        let mut rows = Vec::new();
 4999        let mut rows_inserted = 0;
 5000
 5001        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5002            let cursor = selection.head();
 5003            let row = cursor.row;
 5004
 5005            let point = Point::new(row + 1, 0);
 5006            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5007
 5008            let newline = "\n".to_string();
 5009            edits.push((start_of_line..start_of_line, newline));
 5010
 5011            rows_inserted += 1;
 5012            rows.push(row + rows_inserted);
 5013        }
 5014
 5015        self.transact(window, cx, |editor, window, cx| {
 5016            editor.edit(edits, cx);
 5017
 5018            editor.change_selections(Default::default(), window, cx, |s| {
 5019                let mut index = 0;
 5020                s.move_cursors_with(|map, _, _| {
 5021                    let row = rows[index];
 5022                    index += 1;
 5023
 5024                    let point = Point::new(row, 0);
 5025                    let boundary = map.next_line_boundary(point).1;
 5026                    let clipped = map.clip_point(boundary, Bias::Left);
 5027
 5028                    (clipped, SelectionGoal::None)
 5029                });
 5030            });
 5031
 5032            let mut indent_edits = Vec::new();
 5033            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5034            for row in rows {
 5035                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5036                for (row, indent) in indents {
 5037                    if indent.len == 0 {
 5038                        continue;
 5039                    }
 5040
 5041                    let text = match indent.kind {
 5042                        IndentKind::Space => " ".repeat(indent.len as usize),
 5043                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5044                    };
 5045                    let point = Point::new(row.0, 0);
 5046                    indent_edits.push((point..point, text));
 5047                }
 5048            }
 5049            editor.edit(indent_edits, cx);
 5050        });
 5051    }
 5052
 5053    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5054        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5055            original_indent_columns: Vec::new(),
 5056        });
 5057        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5058    }
 5059
 5060    fn insert_with_autoindent_mode(
 5061        &mut self,
 5062        text: &str,
 5063        autoindent_mode: Option<AutoindentMode>,
 5064        window: &mut Window,
 5065        cx: &mut Context<Self>,
 5066    ) {
 5067        if self.read_only(cx) {
 5068            return;
 5069        }
 5070
 5071        let text: Arc<str> = text.into();
 5072        self.transact(window, cx, |this, window, cx| {
 5073            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5074            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5075                let anchors = {
 5076                    let snapshot = buffer.read(cx);
 5077                    old_selections
 5078                        .iter()
 5079                        .map(|s| {
 5080                            let anchor = snapshot.anchor_after(s.head());
 5081                            s.map(|_| anchor)
 5082                        })
 5083                        .collect::<Vec<_>>()
 5084                };
 5085                buffer.edit(
 5086                    old_selections
 5087                        .iter()
 5088                        .map(|s| (s.start..s.end, text.clone())),
 5089                    autoindent_mode,
 5090                    cx,
 5091                );
 5092                anchors
 5093            });
 5094
 5095            this.change_selections(Default::default(), window, cx, |s| {
 5096                s.select_anchors(selection_anchors);
 5097            });
 5098
 5099            cx.notify();
 5100        });
 5101    }
 5102
 5103    fn trigger_completion_on_input(
 5104        &mut self,
 5105        text: &str,
 5106        trigger_in_words: bool,
 5107        window: &mut Window,
 5108        cx: &mut Context<Self>,
 5109    ) {
 5110        let completions_source = self
 5111            .context_menu
 5112            .borrow()
 5113            .as_ref()
 5114            .and_then(|menu| match menu {
 5115                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5116                CodeContextMenu::CodeActions(_) => None,
 5117            });
 5118
 5119        match completions_source {
 5120            Some(CompletionsMenuSource::Words { .. }) => {
 5121                self.open_or_update_completions_menu(
 5122                    Some(CompletionsMenuSource::Words {
 5123                        ignore_threshold: false,
 5124                    }),
 5125                    None,
 5126                    trigger_in_words,
 5127                    window,
 5128                    cx,
 5129                );
 5130            }
 5131            _ => self.open_or_update_completions_menu(
 5132                None,
 5133                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5134                true,
 5135                window,
 5136                cx,
 5137            ),
 5138        }
 5139    }
 5140
 5141    /// If any empty selections is touching the start of its innermost containing autoclose
 5142    /// region, expand it to select the brackets.
 5143    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5144        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5145        let buffer = self.buffer.read(cx).read(cx);
 5146        let new_selections = self
 5147            .selections_with_autoclose_regions(selections, &buffer)
 5148            .map(|(mut selection, region)| {
 5149                if !selection.is_empty() {
 5150                    return selection;
 5151                }
 5152
 5153                if let Some(region) = region {
 5154                    let mut range = region.range.to_offset(&buffer);
 5155                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5156                        range.start -= region.pair.start.len();
 5157                        if buffer.contains_str_at(range.start, &region.pair.start)
 5158                            && buffer.contains_str_at(range.end, &region.pair.end)
 5159                        {
 5160                            range.end += region.pair.end.len();
 5161                            selection.start = range.start;
 5162                            selection.end = range.end;
 5163
 5164                            return selection;
 5165                        }
 5166                    }
 5167                }
 5168
 5169                let always_treat_brackets_as_autoclosed = buffer
 5170                    .language_settings_at(selection.start, cx)
 5171                    .always_treat_brackets_as_autoclosed;
 5172
 5173                if !always_treat_brackets_as_autoclosed {
 5174                    return selection;
 5175                }
 5176
 5177                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5178                    for (pair, enabled) in scope.brackets() {
 5179                        if !enabled || !pair.close {
 5180                            continue;
 5181                        }
 5182
 5183                        if buffer.contains_str_at(selection.start, &pair.end) {
 5184                            let pair_start_len = pair.start.len();
 5185                            if buffer.contains_str_at(
 5186                                selection.start.saturating_sub(pair_start_len),
 5187                                &pair.start,
 5188                            ) {
 5189                                selection.start -= pair_start_len;
 5190                                selection.end += pair.end.len();
 5191
 5192                                return selection;
 5193                            }
 5194                        }
 5195                    }
 5196                }
 5197
 5198                selection
 5199            })
 5200            .collect();
 5201
 5202        drop(buffer);
 5203        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5204            selections.select(new_selections)
 5205        });
 5206    }
 5207
 5208    /// Iterate the given selections, and for each one, find the smallest surrounding
 5209    /// autoclose region. This uses the ordering of the selections and the autoclose
 5210    /// regions to avoid repeated comparisons.
 5211    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5212        &'a self,
 5213        selections: impl IntoIterator<Item = Selection<D>>,
 5214        buffer: &'a MultiBufferSnapshot,
 5215    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5216        let mut i = 0;
 5217        let mut regions = self.autoclose_regions.as_slice();
 5218        selections.into_iter().map(move |selection| {
 5219            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5220
 5221            let mut enclosing = None;
 5222            while let Some(pair_state) = regions.get(i) {
 5223                if pair_state.range.end.to_offset(buffer) < range.start {
 5224                    regions = &regions[i + 1..];
 5225                    i = 0;
 5226                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5227                    break;
 5228                } else {
 5229                    if pair_state.selection_id == selection.id {
 5230                        enclosing = Some(pair_state);
 5231                    }
 5232                    i += 1;
 5233                }
 5234            }
 5235
 5236            (selection, enclosing)
 5237        })
 5238    }
 5239
 5240    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5241    fn invalidate_autoclose_regions(
 5242        &mut self,
 5243        mut selections: &[Selection<Anchor>],
 5244        buffer: &MultiBufferSnapshot,
 5245    ) {
 5246        self.autoclose_regions.retain(|state| {
 5247            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5248                return false;
 5249            }
 5250
 5251            let mut i = 0;
 5252            while let Some(selection) = selections.get(i) {
 5253                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5254                    selections = &selections[1..];
 5255                    continue;
 5256                }
 5257                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5258                    break;
 5259                }
 5260                if selection.id == state.selection_id {
 5261                    return true;
 5262                } else {
 5263                    i += 1;
 5264                }
 5265            }
 5266            false
 5267        });
 5268    }
 5269
 5270    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5271        let offset = position.to_offset(buffer);
 5272        let (word_range, kind) =
 5273            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5274        if offset > word_range.start && kind == Some(CharKind::Word) {
 5275            Some(
 5276                buffer
 5277                    .text_for_range(word_range.start..offset)
 5278                    .collect::<String>(),
 5279            )
 5280        } else {
 5281            None
 5282        }
 5283    }
 5284
 5285    pub fn visible_excerpts(
 5286        &self,
 5287        cx: &mut Context<Editor>,
 5288    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5289        let Some(project) = self.project() else {
 5290            return HashMap::default();
 5291        };
 5292        let project = project.read(cx);
 5293        let multi_buffer = self.buffer().read(cx);
 5294        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5295        let multi_buffer_visible_start = self
 5296            .scroll_manager
 5297            .anchor()
 5298            .anchor
 5299            .to_point(&multi_buffer_snapshot);
 5300        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5301            multi_buffer_visible_start
 5302                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5303            Bias::Left,
 5304        );
 5305        multi_buffer_snapshot
 5306            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5307            .into_iter()
 5308            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5309            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5310                let buffer_file = project::File::from_dyn(buffer.file())?;
 5311                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5312                let worktree_entry = buffer_worktree
 5313                    .read(cx)
 5314                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5315                if worktree_entry.is_ignored {
 5316                    None
 5317                } else {
 5318                    Some((
 5319                        excerpt_id,
 5320                        (
 5321                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5322                            buffer.version().clone(),
 5323                            excerpt_visible_range,
 5324                        ),
 5325                    ))
 5326                }
 5327            })
 5328            .collect()
 5329    }
 5330
 5331    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5332        TextLayoutDetails {
 5333            text_system: window.text_system().clone(),
 5334            editor_style: self.style.clone().unwrap(),
 5335            rem_size: window.rem_size(),
 5336            scroll_anchor: self.scroll_manager.anchor(),
 5337            visible_rows: self.visible_line_count(),
 5338            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5339        }
 5340    }
 5341
 5342    fn trigger_on_type_formatting(
 5343        &self,
 5344        input: String,
 5345        window: &mut Window,
 5346        cx: &mut Context<Self>,
 5347    ) -> Option<Task<Result<()>>> {
 5348        if input.len() != 1 {
 5349            return None;
 5350        }
 5351
 5352        let project = self.project()?;
 5353        let position = self.selections.newest_anchor().head();
 5354        let (buffer, buffer_position) = self
 5355            .buffer
 5356            .read(cx)
 5357            .text_anchor_for_position(position, cx)?;
 5358
 5359        let settings = language_settings::language_settings(
 5360            buffer
 5361                .read(cx)
 5362                .language_at(buffer_position)
 5363                .map(|l| l.name()),
 5364            buffer.read(cx).file(),
 5365            cx,
 5366        );
 5367        if !settings.use_on_type_format {
 5368            return None;
 5369        }
 5370
 5371        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5372        // hence we do LSP request & edit on host side only — add formats to host's history.
 5373        let push_to_lsp_host_history = true;
 5374        // If this is not the host, append its history with new edits.
 5375        let push_to_client_history = project.read(cx).is_via_collab();
 5376
 5377        let on_type_formatting = project.update(cx, |project, cx| {
 5378            project.on_type_format(
 5379                buffer.clone(),
 5380                buffer_position,
 5381                input,
 5382                push_to_lsp_host_history,
 5383                cx,
 5384            )
 5385        });
 5386        Some(cx.spawn_in(window, async move |editor, cx| {
 5387            if let Some(transaction) = on_type_formatting.await? {
 5388                if push_to_client_history {
 5389                    buffer
 5390                        .update(cx, |buffer, _| {
 5391                            buffer.push_transaction(transaction, Instant::now());
 5392                            buffer.finalize_last_transaction();
 5393                        })
 5394                        .ok();
 5395                }
 5396                editor.update(cx, |editor, cx| {
 5397                    editor.refresh_document_highlights(cx);
 5398                })?;
 5399            }
 5400            Ok(())
 5401        }))
 5402    }
 5403
 5404    pub fn show_word_completions(
 5405        &mut self,
 5406        _: &ShowWordCompletions,
 5407        window: &mut Window,
 5408        cx: &mut Context<Self>,
 5409    ) {
 5410        self.open_or_update_completions_menu(
 5411            Some(CompletionsMenuSource::Words {
 5412                ignore_threshold: true,
 5413            }),
 5414            None,
 5415            false,
 5416            window,
 5417            cx,
 5418        );
 5419    }
 5420
 5421    pub fn show_completions(
 5422        &mut self,
 5423        _: &ShowCompletions,
 5424        window: &mut Window,
 5425        cx: &mut Context<Self>,
 5426    ) {
 5427        self.open_or_update_completions_menu(None, None, false, window, cx);
 5428    }
 5429
 5430    fn open_or_update_completions_menu(
 5431        &mut self,
 5432        requested_source: Option<CompletionsMenuSource>,
 5433        trigger: Option<String>,
 5434        trigger_in_words: bool,
 5435        window: &mut Window,
 5436        cx: &mut Context<Self>,
 5437    ) {
 5438        if self.pending_rename.is_some() {
 5439            return;
 5440        }
 5441
 5442        let completions_source = self
 5443            .context_menu
 5444            .borrow()
 5445            .as_ref()
 5446            .and_then(|menu| match menu {
 5447                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5448                CodeContextMenu::CodeActions(_) => None,
 5449            });
 5450
 5451        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5452
 5453        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5454        // inserted and selected. To handle that case, the start of the selection is used so that
 5455        // the menu starts with all choices.
 5456        let position = self
 5457            .selections
 5458            .newest_anchor()
 5459            .start
 5460            .bias_right(&multibuffer_snapshot);
 5461        if position.diff_base_anchor.is_some() {
 5462            return;
 5463        }
 5464        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5465        let Some(buffer) = buffer_position
 5466            .buffer_id
 5467            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5468        else {
 5469            return;
 5470        };
 5471        let buffer_snapshot = buffer.read(cx).snapshot();
 5472
 5473        let query: Option<Arc<String>> =
 5474            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5475                .map(|query| query.into());
 5476
 5477        drop(multibuffer_snapshot);
 5478
 5479        // Hide the current completions menu when query is empty. Without this, cached
 5480        // completions from before the trigger char may be reused (#32774).
 5481        if query.is_none() {
 5482            let menu_is_open = matches!(
 5483                self.context_menu.borrow().as_ref(),
 5484                Some(CodeContextMenu::Completions(_))
 5485            );
 5486            if menu_is_open {
 5487                self.hide_context_menu(window, cx);
 5488            }
 5489        }
 5490
 5491        let mut ignore_word_threshold = false;
 5492        let provider = match requested_source {
 5493            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5494            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5495                ignore_word_threshold = ignore_threshold;
 5496                None
 5497            }
 5498            Some(CompletionsMenuSource::SnippetChoices)
 5499            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5500                log::error!("bug: SnippetChoices requested_source is not handled");
 5501                None
 5502            }
 5503        };
 5504
 5505        let sort_completions = provider
 5506            .as_ref()
 5507            .is_some_and(|provider| provider.sort_completions());
 5508
 5509        let filter_completions = provider
 5510            .as_ref()
 5511            .is_none_or(|provider| provider.filter_completions());
 5512
 5513        let was_snippets_only = matches!(
 5514            completions_source,
 5515            Some(CompletionsMenuSource::SnippetsOnly)
 5516        );
 5517
 5518        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5519            if filter_completions {
 5520                menu.filter(
 5521                    query.clone().unwrap_or_default(),
 5522                    buffer_position.text_anchor,
 5523                    &buffer,
 5524                    provider.clone(),
 5525                    window,
 5526                    cx,
 5527                );
 5528            }
 5529            // When `is_incomplete` is false, no need to re-query completions when the current query
 5530            // is a suffix of the initial query.
 5531            let was_complete = !menu.is_incomplete;
 5532            if was_complete && !was_snippets_only {
 5533                // If the new query is a suffix of the old query (typing more characters) and
 5534                // the previous result was complete, the existing completions can be filtered.
 5535                //
 5536                // Note that snippet completions are always complete.
 5537                let query_matches = match (&menu.initial_query, &query) {
 5538                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5539                    (None, _) => true,
 5540                    _ => false,
 5541                };
 5542                if query_matches {
 5543                    let position_matches = if menu.initial_position == position {
 5544                        true
 5545                    } else {
 5546                        let snapshot = self.buffer.read(cx).read(cx);
 5547                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5548                    };
 5549                    if position_matches {
 5550                        return;
 5551                    }
 5552                }
 5553            }
 5554        };
 5555
 5556        let Anchor {
 5557            excerpt_id: buffer_excerpt_id,
 5558            text_anchor: buffer_position,
 5559            ..
 5560        } = buffer_position;
 5561
 5562        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5563            buffer_snapshot.surrounding_word(buffer_position, None)
 5564        {
 5565            let word_to_exclude = buffer_snapshot
 5566                .text_for_range(word_range.clone())
 5567                .collect::<String>();
 5568            (
 5569                buffer_snapshot.anchor_before(word_range.start)
 5570                    ..buffer_snapshot.anchor_after(buffer_position),
 5571                Some(word_to_exclude),
 5572            )
 5573        } else {
 5574            (buffer_position..buffer_position, None)
 5575        };
 5576
 5577        let language = buffer_snapshot
 5578            .language_at(buffer_position)
 5579            .map(|language| language.name());
 5580
 5581        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5582            .completions
 5583            .clone();
 5584
 5585        let show_completion_documentation = buffer_snapshot
 5586            .settings_at(buffer_position, cx)
 5587            .show_completion_documentation;
 5588
 5589        // The document can be large, so stay in reasonable bounds when searching for words,
 5590        // otherwise completion pop-up might be slow to appear.
 5591        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5592        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5593        let min_word_search = buffer_snapshot.clip_point(
 5594            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5595            Bias::Left,
 5596        );
 5597        let max_word_search = buffer_snapshot.clip_point(
 5598            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5599            Bias::Right,
 5600        );
 5601        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5602            ..buffer_snapshot.point_to_offset(max_word_search);
 5603
 5604        let skip_digits = query
 5605            .as_ref()
 5606            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5607
 5608        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5609            trigger.as_ref().is_none_or(|trigger| {
 5610                provider.is_completion_trigger(
 5611                    &buffer,
 5612                    position.text_anchor,
 5613                    trigger,
 5614                    trigger_in_words,
 5615                    completions_source.is_some(),
 5616                    cx,
 5617                )
 5618            })
 5619        });
 5620
 5621        let provider_responses = if let Some(provider) = &provider
 5622            && load_provider_completions
 5623        {
 5624            let trigger_character =
 5625                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5626            let completion_context = CompletionContext {
 5627                trigger_kind: match &trigger_character {
 5628                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5629                    None => CompletionTriggerKind::INVOKED,
 5630                },
 5631                trigger_character,
 5632            };
 5633
 5634            provider.completions(
 5635                buffer_excerpt_id,
 5636                &buffer,
 5637                buffer_position,
 5638                completion_context,
 5639                window,
 5640                cx,
 5641            )
 5642        } else {
 5643            Task::ready(Ok(Vec::new()))
 5644        };
 5645
 5646        let load_word_completions = if !self.word_completions_enabled {
 5647            false
 5648        } else if requested_source
 5649            == Some(CompletionsMenuSource::Words {
 5650                ignore_threshold: true,
 5651            })
 5652        {
 5653            true
 5654        } else {
 5655            load_provider_completions
 5656                && completion_settings.words != WordsCompletionMode::Disabled
 5657                && (ignore_word_threshold || {
 5658                    let words_min_length = completion_settings.words_min_length;
 5659                    // check whether word has at least `words_min_length` characters
 5660                    let query_chars = query.iter().flat_map(|q| q.chars());
 5661                    query_chars.take(words_min_length).count() == words_min_length
 5662                })
 5663        };
 5664
 5665        let mut words = if load_word_completions {
 5666            cx.background_spawn({
 5667                let buffer_snapshot = buffer_snapshot.clone();
 5668                async move {
 5669                    buffer_snapshot.words_in_range(WordsQuery {
 5670                        fuzzy_contents: None,
 5671                        range: word_search_range,
 5672                        skip_digits,
 5673                    })
 5674                }
 5675            })
 5676        } else {
 5677            Task::ready(BTreeMap::default())
 5678        };
 5679
 5680        let snippets = if let Some(provider) = &provider
 5681            && provider.show_snippets()
 5682            && let Some(project) = self.project()
 5683        {
 5684            let char_classifier = buffer_snapshot
 5685                .char_classifier_at(buffer_position)
 5686                .scope_context(Some(CharScopeContext::Completion));
 5687            project.update(cx, |project, cx| {
 5688                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5689            })
 5690        } else {
 5691            Task::ready(Ok(CompletionResponse {
 5692                completions: Vec::new(),
 5693                display_options: Default::default(),
 5694                is_incomplete: false,
 5695            }))
 5696        };
 5697
 5698        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5699
 5700        let id = post_inc(&mut self.next_completion_id);
 5701        let task = cx.spawn_in(window, async move |editor, cx| {
 5702            let Ok(()) = editor.update(cx, |this, _| {
 5703                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5704            }) else {
 5705                return;
 5706            };
 5707
 5708            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5709            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5710            let mut completions = Vec::new();
 5711            let mut is_incomplete = false;
 5712            let mut display_options: Option<CompletionDisplayOptions> = None;
 5713            if let Some(provider_responses) = provider_responses.await.log_err()
 5714                && !provider_responses.is_empty()
 5715            {
 5716                for response in provider_responses {
 5717                    completions.extend(response.completions);
 5718                    is_incomplete = is_incomplete || response.is_incomplete;
 5719                    match display_options.as_mut() {
 5720                        None => {
 5721                            display_options = Some(response.display_options);
 5722                        }
 5723                        Some(options) => options.merge(&response.display_options),
 5724                    }
 5725                }
 5726                if completion_settings.words == WordsCompletionMode::Fallback {
 5727                    words = Task::ready(BTreeMap::default());
 5728                }
 5729            }
 5730            let display_options = display_options.unwrap_or_default();
 5731
 5732            let mut words = words.await;
 5733            if let Some(word_to_exclude) = &word_to_exclude {
 5734                words.remove(word_to_exclude);
 5735            }
 5736            for lsp_completion in &completions {
 5737                words.remove(&lsp_completion.new_text);
 5738            }
 5739            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5740                replace_range: word_replace_range.clone(),
 5741                new_text: word.clone(),
 5742                label: CodeLabel::plain(word, None),
 5743                match_start: None,
 5744                snippet_deduplication_key: None,
 5745                icon_path: None,
 5746                documentation: None,
 5747                source: CompletionSource::BufferWord {
 5748                    word_range,
 5749                    resolved: false,
 5750                },
 5751                insert_text_mode: Some(InsertTextMode::AS_IS),
 5752                confirm: None,
 5753            }));
 5754
 5755            completions.extend(
 5756                snippets
 5757                    .await
 5758                    .into_iter()
 5759                    .flat_map(|response| response.completions),
 5760            );
 5761
 5762            let menu = if completions.is_empty() {
 5763                None
 5764            } else {
 5765                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5766                    let languages = editor
 5767                        .workspace
 5768                        .as_ref()
 5769                        .and_then(|(workspace, _)| workspace.upgrade())
 5770                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5771                    let menu = CompletionsMenu::new(
 5772                        id,
 5773                        requested_source.unwrap_or(if load_provider_completions {
 5774                            CompletionsMenuSource::Normal
 5775                        } else {
 5776                            CompletionsMenuSource::SnippetsOnly
 5777                        }),
 5778                        sort_completions,
 5779                        show_completion_documentation,
 5780                        position,
 5781                        query.clone(),
 5782                        is_incomplete,
 5783                        buffer.clone(),
 5784                        completions.into(),
 5785                        display_options,
 5786                        snippet_sort_order,
 5787                        languages,
 5788                        language,
 5789                        cx,
 5790                    );
 5791
 5792                    let query = if filter_completions { query } else { None };
 5793                    let matches_task = menu.do_async_filtering(
 5794                        query.unwrap_or_default(),
 5795                        buffer_position,
 5796                        &buffer,
 5797                        cx,
 5798                    );
 5799                    (menu, matches_task)
 5800                }) else {
 5801                    return;
 5802                };
 5803
 5804                let matches = matches_task.await;
 5805
 5806                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5807                    // Newer menu already set, so exit.
 5808                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5809                        editor.context_menu.borrow().as_ref()
 5810                        && prev_menu.id > id
 5811                    {
 5812                        return;
 5813                    };
 5814
 5815                    // Only valid to take prev_menu because either the new menu is immediately set
 5816                    // below, or the menu is hidden.
 5817                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5818                        editor.context_menu.borrow_mut().take()
 5819                    {
 5820                        let position_matches =
 5821                            if prev_menu.initial_position == menu.initial_position {
 5822                                true
 5823                            } else {
 5824                                let snapshot = editor.buffer.read(cx).read(cx);
 5825                                prev_menu.initial_position.to_offset(&snapshot)
 5826                                    == menu.initial_position.to_offset(&snapshot)
 5827                            };
 5828                        if position_matches {
 5829                            // Preserve markdown cache before `set_filter_results` because it will
 5830                            // try to populate the documentation cache.
 5831                            menu.preserve_markdown_cache(prev_menu);
 5832                        }
 5833                    };
 5834
 5835                    menu.set_filter_results(matches, provider, window, cx);
 5836                }) else {
 5837                    return;
 5838                };
 5839
 5840                menu.visible().then_some(menu)
 5841            };
 5842
 5843            editor
 5844                .update_in(cx, |editor, window, cx| {
 5845                    if editor.focus_handle.is_focused(window)
 5846                        && let Some(menu) = menu
 5847                    {
 5848                        *editor.context_menu.borrow_mut() =
 5849                            Some(CodeContextMenu::Completions(menu));
 5850
 5851                        crate::hover_popover::hide_hover(editor, cx);
 5852                        if editor.show_edit_predictions_in_menu() {
 5853                            editor.update_visible_edit_prediction(window, cx);
 5854                        } else {
 5855                            editor.discard_edit_prediction(false, cx);
 5856                        }
 5857
 5858                        cx.notify();
 5859                        return;
 5860                    }
 5861
 5862                    if editor.completion_tasks.len() <= 1 {
 5863                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5864                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5865                        // If it was already hidden and we don't show edit predictions in the menu,
 5866                        // we should also show the edit prediction when available.
 5867                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5868                            editor.update_visible_edit_prediction(window, cx);
 5869                        }
 5870                    }
 5871                })
 5872                .ok();
 5873        });
 5874
 5875        self.completion_tasks.push((id, task));
 5876    }
 5877
 5878    #[cfg(feature = "test-support")]
 5879    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5880        let menu = self.context_menu.borrow();
 5881        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5882            let completions = menu.completions.borrow();
 5883            Some(completions.to_vec())
 5884        } else {
 5885            None
 5886        }
 5887    }
 5888
 5889    pub fn with_completions_menu_matching_id<R>(
 5890        &self,
 5891        id: CompletionId,
 5892        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5893    ) -> R {
 5894        let mut context_menu = self.context_menu.borrow_mut();
 5895        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5896            return f(None);
 5897        };
 5898        if completions_menu.id != id {
 5899            return f(None);
 5900        }
 5901        f(Some(completions_menu))
 5902    }
 5903
 5904    pub fn confirm_completion(
 5905        &mut self,
 5906        action: &ConfirmCompletion,
 5907        window: &mut Window,
 5908        cx: &mut Context<Self>,
 5909    ) -> Option<Task<Result<()>>> {
 5910        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5911        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5912    }
 5913
 5914    pub fn confirm_completion_insert(
 5915        &mut self,
 5916        _: &ConfirmCompletionInsert,
 5917        window: &mut Window,
 5918        cx: &mut Context<Self>,
 5919    ) -> Option<Task<Result<()>>> {
 5920        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5921        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5922    }
 5923
 5924    pub fn confirm_completion_replace(
 5925        &mut self,
 5926        _: &ConfirmCompletionReplace,
 5927        window: &mut Window,
 5928        cx: &mut Context<Self>,
 5929    ) -> Option<Task<Result<()>>> {
 5930        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5931        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5932    }
 5933
 5934    pub fn compose_completion(
 5935        &mut self,
 5936        action: &ComposeCompletion,
 5937        window: &mut Window,
 5938        cx: &mut Context<Self>,
 5939    ) -> Option<Task<Result<()>>> {
 5940        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5941        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5942    }
 5943
 5944    fn do_completion(
 5945        &mut self,
 5946        item_ix: Option<usize>,
 5947        intent: CompletionIntent,
 5948        window: &mut Window,
 5949        cx: &mut Context<Editor>,
 5950    ) -> Option<Task<Result<()>>> {
 5951        use language::ToOffset as _;
 5952
 5953        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5954        else {
 5955            return None;
 5956        };
 5957
 5958        let candidate_id = {
 5959            let entries = completions_menu.entries.borrow();
 5960            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5961            if self.show_edit_predictions_in_menu() {
 5962                self.discard_edit_prediction(true, cx);
 5963            }
 5964            mat.candidate_id
 5965        };
 5966
 5967        let completion = completions_menu
 5968            .completions
 5969            .borrow()
 5970            .get(candidate_id)?
 5971            .clone();
 5972        cx.stop_propagation();
 5973
 5974        let buffer_handle = completions_menu.buffer.clone();
 5975
 5976        let CompletionEdit {
 5977            new_text,
 5978            snippet,
 5979            replace_range,
 5980        } = process_completion_for_edit(
 5981            &completion,
 5982            intent,
 5983            &buffer_handle,
 5984            &completions_menu.initial_position.text_anchor,
 5985            cx,
 5986        );
 5987
 5988        let buffer = buffer_handle.read(cx);
 5989        let snapshot = self.buffer.read(cx).snapshot(cx);
 5990        let newest_anchor = self.selections.newest_anchor();
 5991        let replace_range_multibuffer = {
 5992            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5993            excerpt.map_range_from_buffer(replace_range.clone())
 5994        };
 5995        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5996            return None;
 5997        }
 5998
 5999        let old_text = buffer
 6000            .text_for_range(replace_range.clone())
 6001            .collect::<String>();
 6002        let lookbehind = newest_anchor
 6003            .start
 6004            .text_anchor
 6005            .to_offset(buffer)
 6006            .saturating_sub(replace_range.start);
 6007        let lookahead = replace_range
 6008            .end
 6009            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6010        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6011        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6012
 6013        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 6014        let mut ranges = Vec::new();
 6015        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6016
 6017        for selection in &selections {
 6018            let range = if selection.id == newest_anchor.id {
 6019                replace_range_multibuffer.clone()
 6020            } else {
 6021                let mut range = selection.range();
 6022
 6023                // if prefix is present, don't duplicate it
 6024                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6025                    range.start = range.start.saturating_sub(lookbehind);
 6026
 6027                    // if suffix is also present, mimic the newest cursor and replace it
 6028                    if selection.id != newest_anchor.id
 6029                        && snapshot.contains_str_at(range.end, suffix)
 6030                    {
 6031                        range.end += lookahead;
 6032                    }
 6033                }
 6034                range
 6035            };
 6036
 6037            ranges.push(range.clone());
 6038
 6039            if !self.linked_edit_ranges.is_empty() {
 6040                let start_anchor = snapshot.anchor_before(range.start);
 6041                let end_anchor = snapshot.anchor_after(range.end);
 6042                if let Some(ranges) = self
 6043                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6044                {
 6045                    for (buffer, edits) in ranges {
 6046                        linked_edits
 6047                            .entry(buffer.clone())
 6048                            .or_default()
 6049                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6050                    }
 6051                }
 6052            }
 6053        }
 6054
 6055        let common_prefix_len = old_text
 6056            .chars()
 6057            .zip(new_text.chars())
 6058            .take_while(|(a, b)| a == b)
 6059            .map(|(a, _)| a.len_utf8())
 6060            .sum::<usize>();
 6061
 6062        cx.emit(EditorEvent::InputHandled {
 6063            utf16_range_to_replace: None,
 6064            text: new_text[common_prefix_len..].into(),
 6065        });
 6066
 6067        self.transact(window, cx, |editor, window, cx| {
 6068            if let Some(mut snippet) = snippet {
 6069                snippet.text = new_text.to_string();
 6070                editor
 6071                    .insert_snippet(&ranges, snippet, window, cx)
 6072                    .log_err();
 6073            } else {
 6074                editor.buffer.update(cx, |multi_buffer, cx| {
 6075                    let auto_indent = match completion.insert_text_mode {
 6076                        Some(InsertTextMode::AS_IS) => None,
 6077                        _ => editor.autoindent_mode.clone(),
 6078                    };
 6079                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6080                    multi_buffer.edit(edits, auto_indent, cx);
 6081                });
 6082            }
 6083            for (buffer, edits) in linked_edits {
 6084                buffer.update(cx, |buffer, cx| {
 6085                    let snapshot = buffer.snapshot();
 6086                    let edits = edits
 6087                        .into_iter()
 6088                        .map(|(range, text)| {
 6089                            use text::ToPoint as TP;
 6090                            let end_point = TP::to_point(&range.end, &snapshot);
 6091                            let start_point = TP::to_point(&range.start, &snapshot);
 6092                            (start_point..end_point, text)
 6093                        })
 6094                        .sorted_by_key(|(range, _)| range.start);
 6095                    buffer.edit(edits, None, cx);
 6096                })
 6097            }
 6098
 6099            editor.refresh_edit_prediction(true, false, window, cx);
 6100        });
 6101        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6102
 6103        let show_new_completions_on_confirm = completion
 6104            .confirm
 6105            .as_ref()
 6106            .is_some_and(|confirm| confirm(intent, window, cx));
 6107        if show_new_completions_on_confirm {
 6108            self.open_or_update_completions_menu(None, None, false, window, cx);
 6109        }
 6110
 6111        let provider = self.completion_provider.as_ref()?;
 6112        drop(completion);
 6113        let apply_edits = provider.apply_additional_edits_for_completion(
 6114            buffer_handle,
 6115            completions_menu.completions.clone(),
 6116            candidate_id,
 6117            true,
 6118            cx,
 6119        );
 6120
 6121        let editor_settings = EditorSettings::get_global(cx);
 6122        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6123            // After the code completion is finished, users often want to know what signatures are needed.
 6124            // so we should automatically call signature_help
 6125            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6126        }
 6127
 6128        Some(cx.foreground_executor().spawn(async move {
 6129            apply_edits.await?;
 6130            Ok(())
 6131        }))
 6132    }
 6133
 6134    pub fn toggle_code_actions(
 6135        &mut self,
 6136        action: &ToggleCodeActions,
 6137        window: &mut Window,
 6138        cx: &mut Context<Self>,
 6139    ) {
 6140        let quick_launch = action.quick_launch;
 6141        let mut context_menu = self.context_menu.borrow_mut();
 6142        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6143            if code_actions.deployed_from == action.deployed_from {
 6144                // Toggle if we're selecting the same one
 6145                *context_menu = None;
 6146                cx.notify();
 6147                return;
 6148            } else {
 6149                // Otherwise, clear it and start a new one
 6150                *context_menu = None;
 6151                cx.notify();
 6152            }
 6153        }
 6154        drop(context_menu);
 6155        let snapshot = self.snapshot(window, cx);
 6156        let deployed_from = action.deployed_from.clone();
 6157        let action = action.clone();
 6158        self.completion_tasks.clear();
 6159        self.discard_edit_prediction(false, cx);
 6160
 6161        let multibuffer_point = match &action.deployed_from {
 6162            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6163                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6164            }
 6165            _ => self
 6166                .selections
 6167                .newest::<Point>(&snapshot.display_snapshot)
 6168                .head(),
 6169        };
 6170        let Some((buffer, buffer_row)) = snapshot
 6171            .buffer_snapshot()
 6172            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6173            .and_then(|(buffer_snapshot, range)| {
 6174                self.buffer()
 6175                    .read(cx)
 6176                    .buffer(buffer_snapshot.remote_id())
 6177                    .map(|buffer| (buffer, range.start.row))
 6178            })
 6179        else {
 6180            return;
 6181        };
 6182        let buffer_id = buffer.read(cx).remote_id();
 6183        let tasks = self
 6184            .tasks
 6185            .get(&(buffer_id, buffer_row))
 6186            .map(|t| Arc::new(t.to_owned()));
 6187
 6188        if !self.focus_handle.is_focused(window) {
 6189            return;
 6190        }
 6191        let project = self.project.clone();
 6192
 6193        let code_actions_task = match deployed_from {
 6194            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6195            _ => self.code_actions(buffer_row, window, cx),
 6196        };
 6197
 6198        let runnable_task = match deployed_from {
 6199            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6200            _ => {
 6201                let mut task_context_task = Task::ready(None);
 6202                if let Some(tasks) = &tasks
 6203                    && let Some(project) = project
 6204                {
 6205                    task_context_task =
 6206                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6207                }
 6208
 6209                cx.spawn_in(window, {
 6210                    let buffer = buffer.clone();
 6211                    async move |editor, cx| {
 6212                        let task_context = task_context_task.await;
 6213
 6214                        let resolved_tasks =
 6215                            tasks
 6216                                .zip(task_context.clone())
 6217                                .map(|(tasks, task_context)| ResolvedTasks {
 6218                                    templates: tasks.resolve(&task_context).collect(),
 6219                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6220                                        multibuffer_point.row,
 6221                                        tasks.column,
 6222                                    )),
 6223                                });
 6224                        let debug_scenarios = editor
 6225                            .update(cx, |editor, cx| {
 6226                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6227                            })?
 6228                            .await;
 6229                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6230                    }
 6231                })
 6232            }
 6233        };
 6234
 6235        cx.spawn_in(window, async move |editor, cx| {
 6236            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6237            let code_actions = code_actions_task.await;
 6238            let spawn_straight_away = quick_launch
 6239                && resolved_tasks
 6240                    .as_ref()
 6241                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6242                && code_actions
 6243                    .as_ref()
 6244                    .is_none_or(|actions| actions.is_empty())
 6245                && debug_scenarios.is_empty();
 6246
 6247            editor.update_in(cx, |editor, window, cx| {
 6248                crate::hover_popover::hide_hover(editor, cx);
 6249                let actions = CodeActionContents::new(
 6250                    resolved_tasks,
 6251                    code_actions,
 6252                    debug_scenarios,
 6253                    task_context.unwrap_or_default(),
 6254                );
 6255
 6256                // Don't show the menu if there are no actions available
 6257                if actions.is_empty() {
 6258                    cx.notify();
 6259                    return Task::ready(Ok(()));
 6260                }
 6261
 6262                *editor.context_menu.borrow_mut() =
 6263                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6264                        buffer,
 6265                        actions,
 6266                        selected_item: Default::default(),
 6267                        scroll_handle: UniformListScrollHandle::default(),
 6268                        deployed_from,
 6269                    }));
 6270                cx.notify();
 6271                if spawn_straight_away
 6272                    && let Some(task) = editor.confirm_code_action(
 6273                        &ConfirmCodeAction { item_ix: Some(0) },
 6274                        window,
 6275                        cx,
 6276                    )
 6277                {
 6278                    return task;
 6279                }
 6280
 6281                Task::ready(Ok(()))
 6282            })
 6283        })
 6284        .detach_and_log_err(cx);
 6285    }
 6286
 6287    fn debug_scenarios(
 6288        &mut self,
 6289        resolved_tasks: &Option<ResolvedTasks>,
 6290        buffer: &Entity<Buffer>,
 6291        cx: &mut App,
 6292    ) -> Task<Vec<task::DebugScenario>> {
 6293        maybe!({
 6294            let project = self.project()?;
 6295            let dap_store = project.read(cx).dap_store();
 6296            let mut scenarios = vec![];
 6297            let resolved_tasks = resolved_tasks.as_ref()?;
 6298            let buffer = buffer.read(cx);
 6299            let language = buffer.language()?;
 6300            let file = buffer.file();
 6301            let debug_adapter = language_settings(language.name().into(), file, cx)
 6302                .debuggers
 6303                .first()
 6304                .map(SharedString::from)
 6305                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6306
 6307            dap_store.update(cx, |dap_store, cx| {
 6308                for (_, task) in &resolved_tasks.templates {
 6309                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6310                        task.original_task().clone(),
 6311                        debug_adapter.clone().into(),
 6312                        task.display_label().to_owned().into(),
 6313                        cx,
 6314                    );
 6315                    scenarios.push(maybe_scenario);
 6316                }
 6317            });
 6318            Some(cx.background_spawn(async move {
 6319                futures::future::join_all(scenarios)
 6320                    .await
 6321                    .into_iter()
 6322                    .flatten()
 6323                    .collect::<Vec<_>>()
 6324            }))
 6325        })
 6326        .unwrap_or_else(|| Task::ready(vec![]))
 6327    }
 6328
 6329    fn code_actions(
 6330        &mut self,
 6331        buffer_row: u32,
 6332        window: &mut Window,
 6333        cx: &mut Context<Self>,
 6334    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6335        let mut task = self.code_actions_task.take();
 6336        cx.spawn_in(window, async move |editor, cx| {
 6337            while let Some(prev_task) = task {
 6338                prev_task.await.log_err();
 6339                task = editor
 6340                    .update(cx, |this, _| this.code_actions_task.take())
 6341                    .ok()?;
 6342            }
 6343
 6344            editor
 6345                .update(cx, |editor, cx| {
 6346                    editor
 6347                        .available_code_actions
 6348                        .clone()
 6349                        .and_then(|(location, code_actions)| {
 6350                            let snapshot = location.buffer.read(cx).snapshot();
 6351                            let point_range = location.range.to_point(&snapshot);
 6352                            let point_range = point_range.start.row..=point_range.end.row;
 6353                            if point_range.contains(&buffer_row) {
 6354                                Some(code_actions)
 6355                            } else {
 6356                                None
 6357                            }
 6358                        })
 6359                })
 6360                .ok()
 6361                .flatten()
 6362        })
 6363    }
 6364
 6365    pub fn confirm_code_action(
 6366        &mut self,
 6367        action: &ConfirmCodeAction,
 6368        window: &mut Window,
 6369        cx: &mut Context<Self>,
 6370    ) -> Option<Task<Result<()>>> {
 6371        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6372
 6373        let actions_menu =
 6374            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6375                menu
 6376            } else {
 6377                return None;
 6378            };
 6379
 6380        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6381        let action = actions_menu.actions.get(action_ix)?;
 6382        let title = action.label();
 6383        let buffer = actions_menu.buffer;
 6384        let workspace = self.workspace()?;
 6385
 6386        match action {
 6387            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6388                workspace.update(cx, |workspace, cx| {
 6389                    workspace.schedule_resolved_task(
 6390                        task_source_kind,
 6391                        resolved_task,
 6392                        false,
 6393                        window,
 6394                        cx,
 6395                    );
 6396
 6397                    Some(Task::ready(Ok(())))
 6398                })
 6399            }
 6400            CodeActionsItem::CodeAction {
 6401                excerpt_id,
 6402                action,
 6403                provider,
 6404            } => {
 6405                let apply_code_action =
 6406                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6407                let workspace = workspace.downgrade();
 6408                Some(cx.spawn_in(window, async move |editor, cx| {
 6409                    let project_transaction = apply_code_action.await?;
 6410                    Self::open_project_transaction(
 6411                        &editor,
 6412                        workspace,
 6413                        project_transaction,
 6414                        title,
 6415                        cx,
 6416                    )
 6417                    .await
 6418                }))
 6419            }
 6420            CodeActionsItem::DebugScenario(scenario) => {
 6421                let context = actions_menu.actions.context;
 6422
 6423                workspace.update(cx, |workspace, cx| {
 6424                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6425                    workspace.start_debug_session(
 6426                        scenario,
 6427                        context,
 6428                        Some(buffer),
 6429                        None,
 6430                        window,
 6431                        cx,
 6432                    );
 6433                });
 6434                Some(Task::ready(Ok(())))
 6435            }
 6436        }
 6437    }
 6438
 6439    pub async fn open_project_transaction(
 6440        editor: &WeakEntity<Editor>,
 6441        workspace: WeakEntity<Workspace>,
 6442        transaction: ProjectTransaction,
 6443        title: String,
 6444        cx: &mut AsyncWindowContext,
 6445    ) -> Result<()> {
 6446        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6447        cx.update(|_, cx| {
 6448            entries.sort_unstable_by_key(|(buffer, _)| {
 6449                buffer.read(cx).file().map(|f| f.path().clone())
 6450            });
 6451        })?;
 6452        if entries.is_empty() {
 6453            return Ok(());
 6454        }
 6455
 6456        // If the project transaction's edits are all contained within this editor, then
 6457        // avoid opening a new editor to display them.
 6458
 6459        if let [(buffer, transaction)] = &*entries {
 6460            let excerpt = editor.update(cx, |editor, cx| {
 6461                editor
 6462                    .buffer()
 6463                    .read(cx)
 6464                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6465            })?;
 6466            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6467                && excerpted_buffer == *buffer
 6468            {
 6469                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6470                    let excerpt_range = excerpt_range.to_offset(buffer);
 6471                    buffer
 6472                        .edited_ranges_for_transaction::<usize>(transaction)
 6473                        .all(|range| {
 6474                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6475                        })
 6476                })?;
 6477
 6478                if all_edits_within_excerpt {
 6479                    return Ok(());
 6480                }
 6481            }
 6482        }
 6483
 6484        let mut ranges_to_highlight = Vec::new();
 6485        let excerpt_buffer = cx.new(|cx| {
 6486            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6487            for (buffer_handle, transaction) in &entries {
 6488                let edited_ranges = buffer_handle
 6489                    .read(cx)
 6490                    .edited_ranges_for_transaction::<Point>(transaction)
 6491                    .collect::<Vec<_>>();
 6492                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6493                    PathKey::for_buffer(buffer_handle, cx),
 6494                    buffer_handle.clone(),
 6495                    edited_ranges,
 6496                    multibuffer_context_lines(cx),
 6497                    cx,
 6498                );
 6499
 6500                ranges_to_highlight.extend(ranges);
 6501            }
 6502            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6503            multibuffer
 6504        })?;
 6505
 6506        workspace.update_in(cx, |workspace, window, cx| {
 6507            let project = workspace.project().clone();
 6508            let editor =
 6509                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6510            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6511            editor.update(cx, |editor, cx| {
 6512                editor.highlight_background::<Self>(
 6513                    &ranges_to_highlight,
 6514                    |theme| theme.colors().editor_highlighted_line_background,
 6515                    cx,
 6516                );
 6517            });
 6518        })?;
 6519
 6520        Ok(())
 6521    }
 6522
 6523    pub fn clear_code_action_providers(&mut self) {
 6524        self.code_action_providers.clear();
 6525        self.available_code_actions.take();
 6526    }
 6527
 6528    pub fn add_code_action_provider(
 6529        &mut self,
 6530        provider: Rc<dyn CodeActionProvider>,
 6531        window: &mut Window,
 6532        cx: &mut Context<Self>,
 6533    ) {
 6534        if self
 6535            .code_action_providers
 6536            .iter()
 6537            .any(|existing_provider| existing_provider.id() == provider.id())
 6538        {
 6539            return;
 6540        }
 6541
 6542        self.code_action_providers.push(provider);
 6543        self.refresh_code_actions(window, cx);
 6544    }
 6545
 6546    pub fn remove_code_action_provider(
 6547        &mut self,
 6548        id: Arc<str>,
 6549        window: &mut Window,
 6550        cx: &mut Context<Self>,
 6551    ) {
 6552        self.code_action_providers
 6553            .retain(|provider| provider.id() != id);
 6554        self.refresh_code_actions(window, cx);
 6555    }
 6556
 6557    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6558        !self.code_action_providers.is_empty()
 6559            && EditorSettings::get_global(cx).toolbar.code_actions
 6560    }
 6561
 6562    pub fn has_available_code_actions(&self) -> bool {
 6563        self.available_code_actions
 6564            .as_ref()
 6565            .is_some_and(|(_, actions)| !actions.is_empty())
 6566    }
 6567
 6568    fn render_inline_code_actions(
 6569        &self,
 6570        icon_size: ui::IconSize,
 6571        display_row: DisplayRow,
 6572        is_active: bool,
 6573        cx: &mut Context<Self>,
 6574    ) -> AnyElement {
 6575        let show_tooltip = !self.context_menu_visible();
 6576        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6577            .icon_size(icon_size)
 6578            .shape(ui::IconButtonShape::Square)
 6579            .icon_color(ui::Color::Hidden)
 6580            .toggle_state(is_active)
 6581            .when(show_tooltip, |this| {
 6582                this.tooltip({
 6583                    let focus_handle = self.focus_handle.clone();
 6584                    move |_window, cx| {
 6585                        Tooltip::for_action_in(
 6586                            "Toggle Code Actions",
 6587                            &ToggleCodeActions {
 6588                                deployed_from: None,
 6589                                quick_launch: false,
 6590                            },
 6591                            &focus_handle,
 6592                            cx,
 6593                        )
 6594                    }
 6595                })
 6596            })
 6597            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6598                window.focus(&editor.focus_handle(cx));
 6599                editor.toggle_code_actions(
 6600                    &crate::actions::ToggleCodeActions {
 6601                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6602                            display_row,
 6603                        )),
 6604                        quick_launch: false,
 6605                    },
 6606                    window,
 6607                    cx,
 6608                );
 6609            }))
 6610            .into_any_element()
 6611    }
 6612
 6613    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6614        &self.context_menu
 6615    }
 6616
 6617    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6618        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6619            cx.background_executor()
 6620                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6621                .await;
 6622
 6623            let (start_buffer, start, _, end, newest_selection) = this
 6624                .update(cx, |this, cx| {
 6625                    let newest_selection = this.selections.newest_anchor().clone();
 6626                    if newest_selection.head().diff_base_anchor.is_some() {
 6627                        return None;
 6628                    }
 6629                    let display_snapshot = this.display_snapshot(cx);
 6630                    let newest_selection_adjusted =
 6631                        this.selections.newest_adjusted(&display_snapshot);
 6632                    let buffer = this.buffer.read(cx);
 6633
 6634                    let (start_buffer, start) =
 6635                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6636                    let (end_buffer, end) =
 6637                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6638
 6639                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6640                })?
 6641                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6642                .context(
 6643                    "Expected selection to lie in a single buffer when refreshing code actions",
 6644                )?;
 6645            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6646                let providers = this.code_action_providers.clone();
 6647                let tasks = this
 6648                    .code_action_providers
 6649                    .iter()
 6650                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6651                    .collect::<Vec<_>>();
 6652                (providers, tasks)
 6653            })?;
 6654
 6655            let mut actions = Vec::new();
 6656            for (provider, provider_actions) in
 6657                providers.into_iter().zip(future::join_all(tasks).await)
 6658            {
 6659                if let Some(provider_actions) = provider_actions.log_err() {
 6660                    actions.extend(provider_actions.into_iter().map(|action| {
 6661                        AvailableCodeAction {
 6662                            excerpt_id: newest_selection.start.excerpt_id,
 6663                            action,
 6664                            provider: provider.clone(),
 6665                        }
 6666                    }));
 6667                }
 6668            }
 6669
 6670            this.update(cx, |this, cx| {
 6671                this.available_code_actions = if actions.is_empty() {
 6672                    None
 6673                } else {
 6674                    Some((
 6675                        Location {
 6676                            buffer: start_buffer,
 6677                            range: start..end,
 6678                        },
 6679                        actions.into(),
 6680                    ))
 6681                };
 6682                cx.notify();
 6683            })
 6684        }));
 6685    }
 6686
 6687    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6688        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6689            self.show_git_blame_inline = false;
 6690
 6691            self.show_git_blame_inline_delay_task =
 6692                Some(cx.spawn_in(window, async move |this, cx| {
 6693                    cx.background_executor().timer(delay).await;
 6694
 6695                    this.update(cx, |this, cx| {
 6696                        this.show_git_blame_inline = true;
 6697                        cx.notify();
 6698                    })
 6699                    .log_err();
 6700                }));
 6701        }
 6702    }
 6703
 6704    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6705        let snapshot = self.snapshot(window, cx);
 6706        let cursor = self
 6707            .selections
 6708            .newest::<Point>(&snapshot.display_snapshot)
 6709            .head();
 6710        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6711        else {
 6712            return;
 6713        };
 6714
 6715        let Some(blame) = self.blame.as_ref() else {
 6716            return;
 6717        };
 6718
 6719        let row_info = RowInfo {
 6720            buffer_id: Some(buffer.remote_id()),
 6721            buffer_row: Some(point.row),
 6722            ..Default::default()
 6723        };
 6724        let Some((buffer, blame_entry)) = blame
 6725            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6726            .flatten()
 6727        else {
 6728            return;
 6729        };
 6730
 6731        let anchor = self.selections.newest_anchor().head();
 6732        let position = self.to_pixel_point(anchor, &snapshot, window);
 6733        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6734            self.show_blame_popover(
 6735                buffer,
 6736                &blame_entry,
 6737                position + last_bounds.origin,
 6738                true,
 6739                cx,
 6740            );
 6741        };
 6742    }
 6743
 6744    fn show_blame_popover(
 6745        &mut self,
 6746        buffer: BufferId,
 6747        blame_entry: &BlameEntry,
 6748        position: gpui::Point<Pixels>,
 6749        ignore_timeout: bool,
 6750        cx: &mut Context<Self>,
 6751    ) {
 6752        if let Some(state) = &mut self.inline_blame_popover {
 6753            state.hide_task.take();
 6754        } else {
 6755            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6756            let blame_entry = blame_entry.clone();
 6757            let show_task = cx.spawn(async move |editor, cx| {
 6758                if !ignore_timeout {
 6759                    cx.background_executor()
 6760                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6761                        .await;
 6762                }
 6763                editor
 6764                    .update(cx, |editor, cx| {
 6765                        editor.inline_blame_popover_show_task.take();
 6766                        let Some(blame) = editor.blame.as_ref() else {
 6767                            return;
 6768                        };
 6769                        let blame = blame.read(cx);
 6770                        let details = blame.details_for_entry(buffer, &blame_entry);
 6771                        let markdown = cx.new(|cx| {
 6772                            Markdown::new(
 6773                                details
 6774                                    .as_ref()
 6775                                    .map(|message| message.message.clone())
 6776                                    .unwrap_or_default(),
 6777                                None,
 6778                                None,
 6779                                cx,
 6780                            )
 6781                        });
 6782                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6783                            position,
 6784                            hide_task: None,
 6785                            popover_bounds: None,
 6786                            popover_state: InlineBlamePopoverState {
 6787                                scroll_handle: ScrollHandle::new(),
 6788                                commit_message: details,
 6789                                markdown,
 6790                            },
 6791                            keyboard_grace: ignore_timeout,
 6792                        });
 6793                        cx.notify();
 6794                    })
 6795                    .ok();
 6796            });
 6797            self.inline_blame_popover_show_task = Some(show_task);
 6798        }
 6799    }
 6800
 6801    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6802        self.inline_blame_popover_show_task.take();
 6803        if let Some(state) = &mut self.inline_blame_popover {
 6804            let hide_task = cx.spawn(async move |editor, cx| {
 6805                if !ignore_timeout {
 6806                    cx.background_executor()
 6807                        .timer(std::time::Duration::from_millis(100))
 6808                        .await;
 6809                }
 6810                editor
 6811                    .update(cx, |editor, cx| {
 6812                        editor.inline_blame_popover.take();
 6813                        cx.notify();
 6814                    })
 6815                    .ok();
 6816            });
 6817            state.hide_task = Some(hide_task);
 6818            true
 6819        } else {
 6820            false
 6821        }
 6822    }
 6823
 6824    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6825        if self.pending_rename.is_some() {
 6826            return None;
 6827        }
 6828
 6829        let provider = self.semantics_provider.clone()?;
 6830        let buffer = self.buffer.read(cx);
 6831        let newest_selection = self.selections.newest_anchor().clone();
 6832        let cursor_position = newest_selection.head();
 6833        let (cursor_buffer, cursor_buffer_position) =
 6834            buffer.text_anchor_for_position(cursor_position, cx)?;
 6835        let (tail_buffer, tail_buffer_position) =
 6836            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6837        if cursor_buffer != tail_buffer {
 6838            return None;
 6839        }
 6840
 6841        let snapshot = cursor_buffer.read(cx).snapshot();
 6842        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6843        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6844        if start_word_range != end_word_range {
 6845            self.document_highlights_task.take();
 6846            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6847            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6848            return None;
 6849        }
 6850
 6851        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6852        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6853            cx.background_executor()
 6854                .timer(Duration::from_millis(debounce))
 6855                .await;
 6856
 6857            let highlights = if let Some(highlights) = cx
 6858                .update(|cx| {
 6859                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6860                })
 6861                .ok()
 6862                .flatten()
 6863            {
 6864                highlights.await.log_err()
 6865            } else {
 6866                None
 6867            };
 6868
 6869            if let Some(highlights) = highlights {
 6870                this.update(cx, |this, cx| {
 6871                    if this.pending_rename.is_some() {
 6872                        return;
 6873                    }
 6874
 6875                    let buffer = this.buffer.read(cx);
 6876                    if buffer
 6877                        .text_anchor_for_position(cursor_position, cx)
 6878                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6879                    {
 6880                        return;
 6881                    }
 6882
 6883                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6884                    let mut write_ranges = Vec::new();
 6885                    let mut read_ranges = Vec::new();
 6886                    for highlight in highlights {
 6887                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6888                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6889                        {
 6890                            let start = highlight
 6891                                .range
 6892                                .start
 6893                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6894                            let end = highlight
 6895                                .range
 6896                                .end
 6897                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6898                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6899                                continue;
 6900                            }
 6901
 6902                            let range =
 6903                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6904                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6905                                write_ranges.push(range);
 6906                            } else {
 6907                                read_ranges.push(range);
 6908                            }
 6909                        }
 6910                    }
 6911
 6912                    this.highlight_background::<DocumentHighlightRead>(
 6913                        &read_ranges,
 6914                        |theme| theme.colors().editor_document_highlight_read_background,
 6915                        cx,
 6916                    );
 6917                    this.highlight_background::<DocumentHighlightWrite>(
 6918                        &write_ranges,
 6919                        |theme| theme.colors().editor_document_highlight_write_background,
 6920                        cx,
 6921                    );
 6922                    cx.notify();
 6923                })
 6924                .log_err();
 6925            }
 6926        }));
 6927        None
 6928    }
 6929
 6930    fn prepare_highlight_query_from_selection(
 6931        &mut self,
 6932        window: &Window,
 6933        cx: &mut Context<Editor>,
 6934    ) -> Option<(String, Range<Anchor>)> {
 6935        if matches!(self.mode, EditorMode::SingleLine) {
 6936            return None;
 6937        }
 6938        if !EditorSettings::get_global(cx).selection_highlight {
 6939            return None;
 6940        }
 6941        if self.selections.count() != 1 || self.selections.line_mode() {
 6942            return None;
 6943        }
 6944        let snapshot = self.snapshot(window, cx);
 6945        let selection = self.selections.newest::<Point>(&snapshot);
 6946        // If the selection spans multiple rows OR it is empty
 6947        if selection.start.row != selection.end.row
 6948            || selection.start.column == selection.end.column
 6949        {
 6950            return None;
 6951        }
 6952        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6953        let query = snapshot
 6954            .buffer_snapshot()
 6955            .text_for_range(selection_anchor_range.clone())
 6956            .collect::<String>();
 6957        if query.trim().is_empty() {
 6958            return None;
 6959        }
 6960        Some((query, selection_anchor_range))
 6961    }
 6962
 6963    fn update_selection_occurrence_highlights(
 6964        &mut self,
 6965        query_text: String,
 6966        query_range: Range<Anchor>,
 6967        multi_buffer_range_to_query: Range<Point>,
 6968        use_debounce: bool,
 6969        window: &mut Window,
 6970        cx: &mut Context<Editor>,
 6971    ) -> Task<()> {
 6972        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6973        cx.spawn_in(window, async move |editor, cx| {
 6974            if use_debounce {
 6975                cx.background_executor()
 6976                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6977                    .await;
 6978            }
 6979            let match_task = cx.background_spawn(async move {
 6980                let buffer_ranges = multi_buffer_snapshot
 6981                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6982                    .into_iter()
 6983                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6984                let mut match_ranges = Vec::new();
 6985                let Ok(regex) = project::search::SearchQuery::text(
 6986                    query_text.clone(),
 6987                    false,
 6988                    false,
 6989                    false,
 6990                    Default::default(),
 6991                    Default::default(),
 6992                    false,
 6993                    None,
 6994                ) else {
 6995                    return Vec::default();
 6996                };
 6997                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6998                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6999                    match_ranges.extend(
 7000                        regex
 7001                            .search(buffer_snapshot, Some(search_range.clone()))
 7002                            .await
 7003                            .into_iter()
 7004                            .filter_map(|match_range| {
 7005                                let match_start = buffer_snapshot
 7006                                    .anchor_after(search_range.start + match_range.start);
 7007                                let match_end = buffer_snapshot
 7008                                    .anchor_before(search_range.start + match_range.end);
 7009                                let match_anchor_range = Anchor::range_in_buffer(
 7010                                    excerpt_id,
 7011                                    buffer_snapshot.remote_id(),
 7012                                    match_start..match_end,
 7013                                );
 7014                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7015                            }),
 7016                    );
 7017                }
 7018                match_ranges
 7019            });
 7020            let match_ranges = match_task.await;
 7021            editor
 7022                .update_in(cx, |editor, _, cx| {
 7023                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7024                    if !match_ranges.is_empty() {
 7025                        editor.highlight_background::<SelectedTextHighlight>(
 7026                            &match_ranges,
 7027                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7028                            cx,
 7029                        )
 7030                    }
 7031                })
 7032                .log_err();
 7033        })
 7034    }
 7035
 7036    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7037        struct NewlineFold;
 7038        let type_id = std::any::TypeId::of::<NewlineFold>();
 7039        if !self.mode.is_single_line() {
 7040            return;
 7041        }
 7042        let snapshot = self.snapshot(window, cx);
 7043        if snapshot.buffer_snapshot().max_point().row == 0 {
 7044            return;
 7045        }
 7046        let task = cx.background_spawn(async move {
 7047            let new_newlines = snapshot
 7048                .buffer_chars_at(0)
 7049                .filter_map(|(c, i)| {
 7050                    if c == '\n' {
 7051                        Some(
 7052                            snapshot.buffer_snapshot().anchor_after(i)
 7053                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7054                        )
 7055                    } else {
 7056                        None
 7057                    }
 7058                })
 7059                .collect::<Vec<_>>();
 7060            let existing_newlines = snapshot
 7061                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7062                .filter_map(|fold| {
 7063                    if fold.placeholder.type_tag == Some(type_id) {
 7064                        Some(fold.range.start..fold.range.end)
 7065                    } else {
 7066                        None
 7067                    }
 7068                })
 7069                .collect::<Vec<_>>();
 7070
 7071            (new_newlines, existing_newlines)
 7072        });
 7073        self.folding_newlines = cx.spawn(async move |this, cx| {
 7074            let (new_newlines, existing_newlines) = task.await;
 7075            if new_newlines == existing_newlines {
 7076                return;
 7077            }
 7078            let placeholder = FoldPlaceholder {
 7079                render: Arc::new(move |_, _, cx| {
 7080                    div()
 7081                        .bg(cx.theme().status().hint_background)
 7082                        .border_b_1()
 7083                        .size_full()
 7084                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7085                        .border_color(cx.theme().status().hint)
 7086                        .child("\\n")
 7087                        .into_any()
 7088                }),
 7089                constrain_width: false,
 7090                merge_adjacent: false,
 7091                type_tag: Some(type_id),
 7092            };
 7093            let creases = new_newlines
 7094                .into_iter()
 7095                .map(|range| Crease::simple(range, placeholder.clone()))
 7096                .collect();
 7097            this.update(cx, |this, cx| {
 7098                this.display_map.update(cx, |display_map, cx| {
 7099                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7100                    display_map.fold(creases, cx);
 7101                });
 7102            })
 7103            .ok();
 7104        });
 7105    }
 7106
 7107    fn refresh_selected_text_highlights(
 7108        &mut self,
 7109        on_buffer_edit: bool,
 7110        window: &mut Window,
 7111        cx: &mut Context<Editor>,
 7112    ) {
 7113        let Some((query_text, query_range)) =
 7114            self.prepare_highlight_query_from_selection(window, cx)
 7115        else {
 7116            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7117            self.quick_selection_highlight_task.take();
 7118            self.debounced_selection_highlight_task.take();
 7119            return;
 7120        };
 7121        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7122        if on_buffer_edit
 7123            || self
 7124                .quick_selection_highlight_task
 7125                .as_ref()
 7126                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7127        {
 7128            let multi_buffer_visible_start = self
 7129                .scroll_manager
 7130                .anchor()
 7131                .anchor
 7132                .to_point(&multi_buffer_snapshot);
 7133            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7134                multi_buffer_visible_start
 7135                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7136                Bias::Left,
 7137            );
 7138            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7139            self.quick_selection_highlight_task = Some((
 7140                query_range.clone(),
 7141                self.update_selection_occurrence_highlights(
 7142                    query_text.clone(),
 7143                    query_range.clone(),
 7144                    multi_buffer_visible_range,
 7145                    false,
 7146                    window,
 7147                    cx,
 7148                ),
 7149            ));
 7150        }
 7151        if on_buffer_edit
 7152            || self
 7153                .debounced_selection_highlight_task
 7154                .as_ref()
 7155                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7156        {
 7157            let multi_buffer_start = multi_buffer_snapshot
 7158                .anchor_before(0)
 7159                .to_point(&multi_buffer_snapshot);
 7160            let multi_buffer_end = multi_buffer_snapshot
 7161                .anchor_after(multi_buffer_snapshot.len())
 7162                .to_point(&multi_buffer_snapshot);
 7163            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7164            self.debounced_selection_highlight_task = Some((
 7165                query_range.clone(),
 7166                self.update_selection_occurrence_highlights(
 7167                    query_text,
 7168                    query_range,
 7169                    multi_buffer_full_range,
 7170                    true,
 7171                    window,
 7172                    cx,
 7173                ),
 7174            ));
 7175        }
 7176    }
 7177
 7178    pub fn refresh_edit_prediction(
 7179        &mut self,
 7180        debounce: bool,
 7181        user_requested: bool,
 7182        window: &mut Window,
 7183        cx: &mut Context<Self>,
 7184    ) -> Option<()> {
 7185        if DisableAiSettings::get_global(cx).disable_ai {
 7186            return None;
 7187        }
 7188
 7189        let provider = self.edit_prediction_provider()?;
 7190        let cursor = self.selections.newest_anchor().head();
 7191        let (buffer, cursor_buffer_position) =
 7192            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7193
 7194        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7195            self.discard_edit_prediction(false, cx);
 7196            return None;
 7197        }
 7198
 7199        self.update_visible_edit_prediction(window, cx);
 7200
 7201        if !user_requested
 7202            && (!self.should_show_edit_predictions()
 7203                || !self.is_focused(window)
 7204                || buffer.read(cx).is_empty())
 7205        {
 7206            self.discard_edit_prediction(false, cx);
 7207            return None;
 7208        }
 7209
 7210        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7211        Some(())
 7212    }
 7213
 7214    fn show_edit_predictions_in_menu(&self) -> bool {
 7215        match self.edit_prediction_settings {
 7216            EditPredictionSettings::Disabled => false,
 7217            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7218        }
 7219    }
 7220
 7221    pub fn edit_predictions_enabled(&self) -> bool {
 7222        match self.edit_prediction_settings {
 7223            EditPredictionSettings::Disabled => false,
 7224            EditPredictionSettings::Enabled { .. } => true,
 7225        }
 7226    }
 7227
 7228    fn edit_prediction_requires_modifier(&self) -> bool {
 7229        match self.edit_prediction_settings {
 7230            EditPredictionSettings::Disabled => false,
 7231            EditPredictionSettings::Enabled {
 7232                preview_requires_modifier,
 7233                ..
 7234            } => preview_requires_modifier,
 7235        }
 7236    }
 7237
 7238    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7239        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7240            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7241            self.discard_edit_prediction(false, cx);
 7242        } else {
 7243            let selection = self.selections.newest_anchor();
 7244            let cursor = selection.head();
 7245
 7246            if let Some((buffer, cursor_buffer_position)) =
 7247                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7248            {
 7249                self.edit_prediction_settings =
 7250                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7251            }
 7252        }
 7253    }
 7254
 7255    fn edit_prediction_settings_at_position(
 7256        &self,
 7257        buffer: &Entity<Buffer>,
 7258        buffer_position: language::Anchor,
 7259        cx: &App,
 7260    ) -> EditPredictionSettings {
 7261        if !self.mode.is_full()
 7262            || !self.show_edit_predictions_override.unwrap_or(true)
 7263            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7264        {
 7265            return EditPredictionSettings::Disabled;
 7266        }
 7267
 7268        let buffer = buffer.read(cx);
 7269
 7270        let file = buffer.file();
 7271
 7272        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7273            return EditPredictionSettings::Disabled;
 7274        };
 7275
 7276        let by_provider = matches!(
 7277            self.menu_edit_predictions_policy,
 7278            MenuEditPredictionsPolicy::ByProvider
 7279        );
 7280
 7281        let show_in_menu = by_provider
 7282            && self
 7283                .edit_prediction_provider
 7284                .as_ref()
 7285                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7286
 7287        let preview_requires_modifier =
 7288            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7289
 7290        EditPredictionSettings::Enabled {
 7291            show_in_menu,
 7292            preview_requires_modifier,
 7293        }
 7294    }
 7295
 7296    fn should_show_edit_predictions(&self) -> bool {
 7297        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7298    }
 7299
 7300    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7301        matches!(
 7302            self.edit_prediction_preview,
 7303            EditPredictionPreview::Active { .. }
 7304        )
 7305    }
 7306
 7307    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7308        let cursor = self.selections.newest_anchor().head();
 7309        if let Some((buffer, cursor_position)) =
 7310            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7311        {
 7312            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7313        } else {
 7314            false
 7315        }
 7316    }
 7317
 7318    pub fn supports_minimap(&self, cx: &App) -> bool {
 7319        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7320    }
 7321
 7322    fn edit_predictions_enabled_in_buffer(
 7323        &self,
 7324        buffer: &Entity<Buffer>,
 7325        buffer_position: language::Anchor,
 7326        cx: &App,
 7327    ) -> bool {
 7328        maybe!({
 7329            if self.read_only(cx) {
 7330                return Some(false);
 7331            }
 7332            let provider = self.edit_prediction_provider()?;
 7333            if !provider.is_enabled(buffer, buffer_position, cx) {
 7334                return Some(false);
 7335            }
 7336            let buffer = buffer.read(cx);
 7337            let Some(file) = buffer.file() else {
 7338                return Some(true);
 7339            };
 7340            let settings = all_language_settings(Some(file), cx);
 7341            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7342        })
 7343        .unwrap_or(false)
 7344    }
 7345
 7346    fn cycle_edit_prediction(
 7347        &mut self,
 7348        direction: Direction,
 7349        window: &mut Window,
 7350        cx: &mut Context<Self>,
 7351    ) -> Option<()> {
 7352        let provider = self.edit_prediction_provider()?;
 7353        let cursor = self.selections.newest_anchor().head();
 7354        let (buffer, cursor_buffer_position) =
 7355            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7356        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7357            return None;
 7358        }
 7359
 7360        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7361        self.update_visible_edit_prediction(window, cx);
 7362
 7363        Some(())
 7364    }
 7365
 7366    pub fn show_edit_prediction(
 7367        &mut self,
 7368        _: &ShowEditPrediction,
 7369        window: &mut Window,
 7370        cx: &mut Context<Self>,
 7371    ) {
 7372        if !self.has_active_edit_prediction() {
 7373            self.refresh_edit_prediction(false, true, window, cx);
 7374            return;
 7375        }
 7376
 7377        self.update_visible_edit_prediction(window, cx);
 7378    }
 7379
 7380    pub fn display_cursor_names(
 7381        &mut self,
 7382        _: &DisplayCursorNames,
 7383        window: &mut Window,
 7384        cx: &mut Context<Self>,
 7385    ) {
 7386        self.show_cursor_names(window, cx);
 7387    }
 7388
 7389    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7390        self.show_cursor_names = true;
 7391        cx.notify();
 7392        cx.spawn_in(window, async move |this, cx| {
 7393            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7394            this.update(cx, |this, cx| {
 7395                this.show_cursor_names = false;
 7396                cx.notify()
 7397            })
 7398            .ok()
 7399        })
 7400        .detach();
 7401    }
 7402
 7403    pub fn next_edit_prediction(
 7404        &mut self,
 7405        _: &NextEditPrediction,
 7406        window: &mut Window,
 7407        cx: &mut Context<Self>,
 7408    ) {
 7409        if self.has_active_edit_prediction() {
 7410            self.cycle_edit_prediction(Direction::Next, window, cx);
 7411        } else {
 7412            let is_copilot_disabled = self
 7413                .refresh_edit_prediction(false, true, window, cx)
 7414                .is_none();
 7415            if is_copilot_disabled {
 7416                cx.propagate();
 7417            }
 7418        }
 7419    }
 7420
 7421    pub fn previous_edit_prediction(
 7422        &mut self,
 7423        _: &PreviousEditPrediction,
 7424        window: &mut Window,
 7425        cx: &mut Context<Self>,
 7426    ) {
 7427        if self.has_active_edit_prediction() {
 7428            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7429        } else {
 7430            let is_copilot_disabled = self
 7431                .refresh_edit_prediction(false, true, window, cx)
 7432                .is_none();
 7433            if is_copilot_disabled {
 7434                cx.propagate();
 7435            }
 7436        }
 7437    }
 7438
 7439    pub fn accept_edit_prediction(
 7440        &mut self,
 7441        _: &AcceptEditPrediction,
 7442        window: &mut Window,
 7443        cx: &mut Context<Self>,
 7444    ) {
 7445        if self.show_edit_predictions_in_menu() {
 7446            self.hide_context_menu(window, cx);
 7447        }
 7448
 7449        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7450            return;
 7451        };
 7452
 7453        match &active_edit_prediction.completion {
 7454            EditPrediction::MoveWithin { target, .. } => {
 7455                let target = *target;
 7456
 7457                if let Some(position_map) = &self.last_position_map {
 7458                    if position_map
 7459                        .visible_row_range
 7460                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7461                        || !self.edit_prediction_requires_modifier()
 7462                    {
 7463                        self.unfold_ranges(&[target..target], true, false, cx);
 7464                        // Note that this is also done in vim's handler of the Tab action.
 7465                        self.change_selections(
 7466                            SelectionEffects::scroll(Autoscroll::newest()),
 7467                            window,
 7468                            cx,
 7469                            |selections| {
 7470                                selections.select_anchor_ranges([target..target]);
 7471                            },
 7472                        );
 7473                        self.clear_row_highlights::<EditPredictionPreview>();
 7474
 7475                        self.edit_prediction_preview
 7476                            .set_previous_scroll_position(None);
 7477                    } else {
 7478                        self.edit_prediction_preview
 7479                            .set_previous_scroll_position(Some(
 7480                                position_map.snapshot.scroll_anchor,
 7481                            ));
 7482
 7483                        self.highlight_rows::<EditPredictionPreview>(
 7484                            target..target,
 7485                            cx.theme().colors().editor_highlighted_line_background,
 7486                            RowHighlightOptions {
 7487                                autoscroll: true,
 7488                                ..Default::default()
 7489                            },
 7490                            cx,
 7491                        );
 7492                        self.request_autoscroll(Autoscroll::fit(), cx);
 7493                    }
 7494                }
 7495            }
 7496            EditPrediction::MoveOutside { snapshot, target } => {
 7497                if let Some(workspace) = self.workspace() {
 7498                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7499                        .detach_and_log_err(cx);
 7500                }
 7501            }
 7502            EditPrediction::Edit { edits, .. } => {
 7503                self.report_edit_prediction_event(
 7504                    active_edit_prediction.completion_id.clone(),
 7505                    true,
 7506                    cx,
 7507                );
 7508
 7509                if let Some(provider) = self.edit_prediction_provider() {
 7510                    provider.accept(cx);
 7511                }
 7512
 7513                // Store the transaction ID and selections before applying the edit
 7514                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7515
 7516                let snapshot = self.buffer.read(cx).snapshot(cx);
 7517                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7518
 7519                self.buffer.update(cx, |buffer, cx| {
 7520                    buffer.edit(edits.iter().cloned(), None, cx)
 7521                });
 7522
 7523                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7524                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7525                });
 7526
 7527                let selections = self.selections.disjoint_anchors_arc();
 7528                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7529                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7530                    if has_new_transaction {
 7531                        self.selection_history
 7532                            .insert_transaction(transaction_id_now, selections);
 7533                    }
 7534                }
 7535
 7536                self.update_visible_edit_prediction(window, cx);
 7537                if self.active_edit_prediction.is_none() {
 7538                    self.refresh_edit_prediction(true, true, window, cx);
 7539                }
 7540
 7541                cx.notify();
 7542            }
 7543        }
 7544
 7545        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7546    }
 7547
 7548    pub fn accept_partial_edit_prediction(
 7549        &mut self,
 7550        _: &AcceptPartialEditPrediction,
 7551        window: &mut Window,
 7552        cx: &mut Context<Self>,
 7553    ) {
 7554        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7555            return;
 7556        };
 7557        if self.selections.count() != 1 {
 7558            return;
 7559        }
 7560
 7561        match &active_edit_prediction.completion {
 7562            EditPrediction::MoveWithin { target, .. } => {
 7563                let target = *target;
 7564                self.change_selections(
 7565                    SelectionEffects::scroll(Autoscroll::newest()),
 7566                    window,
 7567                    cx,
 7568                    |selections| {
 7569                        selections.select_anchor_ranges([target..target]);
 7570                    },
 7571                );
 7572            }
 7573            EditPrediction::MoveOutside { snapshot, target } => {
 7574                if let Some(workspace) = self.workspace() {
 7575                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7576                        .detach_and_log_err(cx);
 7577                }
 7578            }
 7579            EditPrediction::Edit { edits, .. } => {
 7580                self.report_edit_prediction_event(
 7581                    active_edit_prediction.completion_id.clone(),
 7582                    true,
 7583                    cx,
 7584                );
 7585
 7586                // Find an insertion that starts at the cursor position.
 7587                let snapshot = self.buffer.read(cx).snapshot(cx);
 7588                let cursor_offset = self
 7589                    .selections
 7590                    .newest::<usize>(&self.display_snapshot(cx))
 7591                    .head();
 7592                let insertion = edits.iter().find_map(|(range, text)| {
 7593                    let range = range.to_offset(&snapshot);
 7594                    if range.is_empty() && range.start == cursor_offset {
 7595                        Some(text)
 7596                    } else {
 7597                        None
 7598                    }
 7599                });
 7600
 7601                if let Some(text) = insertion {
 7602                    let mut partial_completion = text
 7603                        .chars()
 7604                        .by_ref()
 7605                        .take_while(|c| c.is_alphabetic())
 7606                        .collect::<String>();
 7607                    if partial_completion.is_empty() {
 7608                        partial_completion = text
 7609                            .chars()
 7610                            .by_ref()
 7611                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7612                            .collect::<String>();
 7613                    }
 7614
 7615                    cx.emit(EditorEvent::InputHandled {
 7616                        utf16_range_to_replace: None,
 7617                        text: partial_completion.clone().into(),
 7618                    });
 7619
 7620                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7621
 7622                    self.refresh_edit_prediction(true, true, window, cx);
 7623                    cx.notify();
 7624                } else {
 7625                    self.accept_edit_prediction(&Default::default(), window, cx);
 7626                }
 7627            }
 7628        }
 7629    }
 7630
 7631    fn discard_edit_prediction(
 7632        &mut self,
 7633        should_report_edit_prediction_event: bool,
 7634        cx: &mut Context<Self>,
 7635    ) -> bool {
 7636        if should_report_edit_prediction_event {
 7637            let completion_id = self
 7638                .active_edit_prediction
 7639                .as_ref()
 7640                .and_then(|active_completion| active_completion.completion_id.clone());
 7641
 7642            self.report_edit_prediction_event(completion_id, false, cx);
 7643        }
 7644
 7645        if let Some(provider) = self.edit_prediction_provider() {
 7646            provider.discard(cx);
 7647        }
 7648
 7649        self.take_active_edit_prediction(cx)
 7650    }
 7651
 7652    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7653        let Some(provider) = self.edit_prediction_provider() else {
 7654            return;
 7655        };
 7656
 7657        let Some((_, buffer, _)) = self
 7658            .buffer
 7659            .read(cx)
 7660            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7661        else {
 7662            return;
 7663        };
 7664
 7665        let extension = buffer
 7666            .read(cx)
 7667            .file()
 7668            .and_then(|file| Some(file.path().extension()?.to_string()));
 7669
 7670        let event_type = match accepted {
 7671            true => "Edit Prediction Accepted",
 7672            false => "Edit Prediction Discarded",
 7673        };
 7674        telemetry::event!(
 7675            event_type,
 7676            provider = provider.name(),
 7677            prediction_id = id,
 7678            suggestion_accepted = accepted,
 7679            file_extension = extension,
 7680        );
 7681    }
 7682
 7683    fn open_editor_at_anchor(
 7684        snapshot: &language::BufferSnapshot,
 7685        target: language::Anchor,
 7686        workspace: &Entity<Workspace>,
 7687        window: &mut Window,
 7688        cx: &mut App,
 7689    ) -> Task<Result<()>> {
 7690        workspace.update(cx, |workspace, cx| {
 7691            let path = snapshot.file().map(|file| file.full_path(cx));
 7692            let Some(path) =
 7693                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7694            else {
 7695                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7696            };
 7697            let target = text::ToPoint::to_point(&target, snapshot);
 7698            let item = workspace.open_path(path, None, true, window, cx);
 7699            window.spawn(cx, async move |cx| {
 7700                let Some(editor) = item.await?.downcast::<Editor>() else {
 7701                    return Ok(());
 7702                };
 7703                editor
 7704                    .update_in(cx, |editor, window, cx| {
 7705                        editor.go_to_singleton_buffer_point(target, window, cx);
 7706                    })
 7707                    .ok();
 7708                anyhow::Ok(())
 7709            })
 7710        })
 7711    }
 7712
 7713    pub fn has_active_edit_prediction(&self) -> bool {
 7714        self.active_edit_prediction.is_some()
 7715    }
 7716
 7717    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7718        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7719            return false;
 7720        };
 7721
 7722        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7723        self.clear_highlights::<EditPredictionHighlight>(cx);
 7724        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7725        true
 7726    }
 7727
 7728    /// Returns true when we're displaying the edit prediction popover below the cursor
 7729    /// like we are not previewing and the LSP autocomplete menu is visible
 7730    /// or we are in `when_holding_modifier` mode.
 7731    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7732        if self.edit_prediction_preview_is_active()
 7733            || !self.show_edit_predictions_in_menu()
 7734            || !self.edit_predictions_enabled()
 7735        {
 7736            return false;
 7737        }
 7738
 7739        if self.has_visible_completions_menu() {
 7740            return true;
 7741        }
 7742
 7743        has_completion && self.edit_prediction_requires_modifier()
 7744    }
 7745
 7746    fn handle_modifiers_changed(
 7747        &mut self,
 7748        modifiers: Modifiers,
 7749        position_map: &PositionMap,
 7750        window: &mut Window,
 7751        cx: &mut Context<Self>,
 7752    ) {
 7753        // Ensure that the edit prediction preview is updated, even when not
 7754        // enabled, if there's an active edit prediction preview.
 7755        if self.show_edit_predictions_in_menu()
 7756            || matches!(
 7757                self.edit_prediction_preview,
 7758                EditPredictionPreview::Active { .. }
 7759            )
 7760        {
 7761            self.update_edit_prediction_preview(&modifiers, window, cx);
 7762        }
 7763
 7764        self.update_selection_mode(&modifiers, position_map, window, cx);
 7765
 7766        let mouse_position = window.mouse_position();
 7767        if !position_map.text_hitbox.is_hovered(window) {
 7768            return;
 7769        }
 7770
 7771        self.update_hovered_link(
 7772            position_map.point_for_position(mouse_position),
 7773            &position_map.snapshot,
 7774            modifiers,
 7775            window,
 7776            cx,
 7777        )
 7778    }
 7779
 7780    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7781        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7782            MultiCursorModifier::Alt => modifiers.secondary(),
 7783            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7784        }
 7785    }
 7786
 7787    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7788        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7789            MultiCursorModifier::Alt => modifiers.alt,
 7790            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7791        }
 7792    }
 7793
 7794    fn columnar_selection_mode(
 7795        modifiers: &Modifiers,
 7796        cx: &mut Context<Self>,
 7797    ) -> Option<ColumnarMode> {
 7798        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7799            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7800                Some(ColumnarMode::FromMouse)
 7801            } else if Self::is_alt_pressed(modifiers, cx) {
 7802                Some(ColumnarMode::FromSelection)
 7803            } else {
 7804                None
 7805            }
 7806        } else {
 7807            None
 7808        }
 7809    }
 7810
 7811    fn update_selection_mode(
 7812        &mut self,
 7813        modifiers: &Modifiers,
 7814        position_map: &PositionMap,
 7815        window: &mut Window,
 7816        cx: &mut Context<Self>,
 7817    ) {
 7818        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7819            return;
 7820        };
 7821        if self.selections.pending_anchor().is_none() {
 7822            return;
 7823        }
 7824
 7825        let mouse_position = window.mouse_position();
 7826        let point_for_position = position_map.point_for_position(mouse_position);
 7827        let position = point_for_position.previous_valid;
 7828
 7829        self.select(
 7830            SelectPhase::BeginColumnar {
 7831                position,
 7832                reset: false,
 7833                mode,
 7834                goal_column: point_for_position.exact_unclipped.column(),
 7835            },
 7836            window,
 7837            cx,
 7838        );
 7839    }
 7840
 7841    fn update_edit_prediction_preview(
 7842        &mut self,
 7843        modifiers: &Modifiers,
 7844        window: &mut Window,
 7845        cx: &mut Context<Self>,
 7846    ) {
 7847        let mut modifiers_held = false;
 7848        if let Some(accept_keystroke) = self
 7849            .accept_edit_prediction_keybind(false, window, cx)
 7850            .keystroke()
 7851        {
 7852            modifiers_held = modifiers_held
 7853                || (accept_keystroke.modifiers() == modifiers
 7854                    && accept_keystroke.modifiers().modified());
 7855        };
 7856        if let Some(accept_partial_keystroke) = self
 7857            .accept_edit_prediction_keybind(true, window, cx)
 7858            .keystroke()
 7859        {
 7860            modifiers_held = modifiers_held
 7861                || (accept_partial_keystroke.modifiers() == modifiers
 7862                    && accept_partial_keystroke.modifiers().modified());
 7863        }
 7864
 7865        if modifiers_held {
 7866            if matches!(
 7867                self.edit_prediction_preview,
 7868                EditPredictionPreview::Inactive { .. }
 7869            ) {
 7870                self.edit_prediction_preview = EditPredictionPreview::Active {
 7871                    previous_scroll_position: None,
 7872                    since: Instant::now(),
 7873                };
 7874
 7875                self.update_visible_edit_prediction(window, cx);
 7876                cx.notify();
 7877            }
 7878        } else if let EditPredictionPreview::Active {
 7879            previous_scroll_position,
 7880            since,
 7881        } = self.edit_prediction_preview
 7882        {
 7883            if let (Some(previous_scroll_position), Some(position_map)) =
 7884                (previous_scroll_position, self.last_position_map.as_ref())
 7885            {
 7886                self.set_scroll_position(
 7887                    previous_scroll_position
 7888                        .scroll_position(&position_map.snapshot.display_snapshot),
 7889                    window,
 7890                    cx,
 7891                );
 7892            }
 7893
 7894            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7895                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7896            };
 7897            self.clear_row_highlights::<EditPredictionPreview>();
 7898            self.update_visible_edit_prediction(window, cx);
 7899            cx.notify();
 7900        }
 7901    }
 7902
 7903    fn update_visible_edit_prediction(
 7904        &mut self,
 7905        _window: &mut Window,
 7906        cx: &mut Context<Self>,
 7907    ) -> Option<()> {
 7908        if DisableAiSettings::get_global(cx).disable_ai {
 7909            return None;
 7910        }
 7911
 7912        if self.ime_transaction.is_some() {
 7913            self.discard_edit_prediction(false, cx);
 7914            return None;
 7915        }
 7916
 7917        let selection = self.selections.newest_anchor();
 7918        let cursor = selection.head();
 7919        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7920        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7921        let excerpt_id = cursor.excerpt_id;
 7922
 7923        let show_in_menu = self.show_edit_predictions_in_menu();
 7924        let completions_menu_has_precedence = !show_in_menu
 7925            && (self.context_menu.borrow().is_some()
 7926                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7927
 7928        if completions_menu_has_precedence
 7929            || !offset_selection.is_empty()
 7930            || self
 7931                .active_edit_prediction
 7932                .as_ref()
 7933                .is_some_and(|completion| {
 7934                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7935                        return false;
 7936                    };
 7937                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7938                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7939                    !invalidation_range.contains(&offset_selection.head())
 7940                })
 7941        {
 7942            self.discard_edit_prediction(false, cx);
 7943            return None;
 7944        }
 7945
 7946        self.take_active_edit_prediction(cx);
 7947        let Some(provider) = self.edit_prediction_provider() else {
 7948            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7949            return None;
 7950        };
 7951
 7952        let (buffer, cursor_buffer_position) =
 7953            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7954
 7955        self.edit_prediction_settings =
 7956            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7957
 7958        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7959
 7960        if self.edit_prediction_indent_conflict {
 7961            let cursor_point = cursor.to_point(&multibuffer);
 7962
 7963            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7964
 7965            if let Some((_, indent)) = indents.iter().next()
 7966                && indent.len == cursor_point.column
 7967            {
 7968                self.edit_prediction_indent_conflict = false;
 7969            }
 7970        }
 7971
 7972        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7973
 7974        let (completion_id, edits, edit_preview) = match edit_prediction {
 7975            edit_prediction::EditPrediction::Local {
 7976                id,
 7977                edits,
 7978                edit_preview,
 7979            } => (id, edits, edit_preview),
 7980            edit_prediction::EditPrediction::Jump {
 7981                id,
 7982                snapshot,
 7983                target,
 7984            } => {
 7985                self.stale_edit_prediction_in_menu = None;
 7986                self.active_edit_prediction = Some(EditPredictionState {
 7987                    inlay_ids: vec![],
 7988                    completion: EditPrediction::MoveOutside { snapshot, target },
 7989                    completion_id: id,
 7990                    invalidation_range: None,
 7991                });
 7992                cx.notify();
 7993                return Some(());
 7994            }
 7995        };
 7996
 7997        let edits = edits
 7998            .into_iter()
 7999            .flat_map(|(range, new_text)| {
 8000                Some((
 8001                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8002                    new_text,
 8003                ))
 8004            })
 8005            .collect::<Vec<_>>();
 8006        if edits.is_empty() {
 8007            return None;
 8008        }
 8009
 8010        let first_edit_start = edits.first().unwrap().0.start;
 8011        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8012        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8013
 8014        let last_edit_end = edits.last().unwrap().0.end;
 8015        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8016        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8017
 8018        let cursor_row = cursor.to_point(&multibuffer).row;
 8019
 8020        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8021
 8022        let mut inlay_ids = Vec::new();
 8023        let invalidation_row_range;
 8024        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8025            Some(cursor_row..edit_end_row)
 8026        } else if cursor_row > edit_end_row {
 8027            Some(edit_start_row..cursor_row)
 8028        } else {
 8029            None
 8030        };
 8031        let supports_jump = self
 8032            .edit_prediction_provider
 8033            .as_ref()
 8034            .map(|provider| provider.provider.supports_jump_to_edit())
 8035            .unwrap_or(true);
 8036
 8037        let is_move = supports_jump
 8038            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8039        let completion = if is_move {
 8040            invalidation_row_range =
 8041                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8042            let target = first_edit_start;
 8043            EditPrediction::MoveWithin { target, snapshot }
 8044        } else {
 8045            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8046                && !self.edit_predictions_hidden_for_vim_mode;
 8047
 8048            if show_completions_in_buffer {
 8049                if edits
 8050                    .iter()
 8051                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8052                {
 8053                    let mut inlays = Vec::new();
 8054                    for (range, new_text) in &edits {
 8055                        let inlay = Inlay::edit_prediction(
 8056                            post_inc(&mut self.next_inlay_id),
 8057                            range.start,
 8058                            new_text.as_ref(),
 8059                        );
 8060                        inlay_ids.push(inlay.id);
 8061                        inlays.push(inlay);
 8062                    }
 8063
 8064                    self.splice_inlays(&[], inlays, cx);
 8065                } else {
 8066                    let background_color = cx.theme().status().deleted_background;
 8067                    self.highlight_text::<EditPredictionHighlight>(
 8068                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8069                        HighlightStyle {
 8070                            background_color: Some(background_color),
 8071                            ..Default::default()
 8072                        },
 8073                        cx,
 8074                    );
 8075                }
 8076            }
 8077
 8078            invalidation_row_range = edit_start_row..edit_end_row;
 8079
 8080            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8081                if provider.show_tab_accept_marker() {
 8082                    EditDisplayMode::TabAccept
 8083                } else {
 8084                    EditDisplayMode::Inline
 8085                }
 8086            } else {
 8087                EditDisplayMode::DiffPopover
 8088            };
 8089
 8090            EditPrediction::Edit {
 8091                edits,
 8092                edit_preview,
 8093                display_mode,
 8094                snapshot,
 8095            }
 8096        };
 8097
 8098        let invalidation_range = multibuffer
 8099            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8100            ..multibuffer.anchor_after(Point::new(
 8101                invalidation_row_range.end,
 8102                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8103            ));
 8104
 8105        self.stale_edit_prediction_in_menu = None;
 8106        self.active_edit_prediction = Some(EditPredictionState {
 8107            inlay_ids,
 8108            completion,
 8109            completion_id,
 8110            invalidation_range: Some(invalidation_range),
 8111        });
 8112
 8113        cx.notify();
 8114
 8115        Some(())
 8116    }
 8117
 8118    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8119        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8120    }
 8121
 8122    fn clear_tasks(&mut self) {
 8123        self.tasks.clear()
 8124    }
 8125
 8126    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8127        if self.tasks.insert(key, value).is_some() {
 8128            // This case should hopefully be rare, but just in case...
 8129            log::error!(
 8130                "multiple different run targets found on a single line, only the last target will be rendered"
 8131            )
 8132        }
 8133    }
 8134
 8135    /// Get all display points of breakpoints that will be rendered within editor
 8136    ///
 8137    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8138    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8139    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8140    fn active_breakpoints(
 8141        &self,
 8142        range: Range<DisplayRow>,
 8143        window: &mut Window,
 8144        cx: &mut Context<Self>,
 8145    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8146        let mut breakpoint_display_points = HashMap::default();
 8147
 8148        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8149            return breakpoint_display_points;
 8150        };
 8151
 8152        let snapshot = self.snapshot(window, cx);
 8153
 8154        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8155        let Some(project) = self.project() else {
 8156            return breakpoint_display_points;
 8157        };
 8158
 8159        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8160            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8161
 8162        for (buffer_snapshot, range, excerpt_id) in
 8163            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8164        {
 8165            let Some(buffer) = project
 8166                .read(cx)
 8167                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8168            else {
 8169                continue;
 8170            };
 8171            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8172                &buffer,
 8173                Some(
 8174                    buffer_snapshot.anchor_before(range.start)
 8175                        ..buffer_snapshot.anchor_after(range.end),
 8176                ),
 8177                buffer_snapshot,
 8178                cx,
 8179            );
 8180            for (breakpoint, state) in breakpoints {
 8181                let multi_buffer_anchor =
 8182                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8183                let position = multi_buffer_anchor
 8184                    .to_point(&multi_buffer_snapshot)
 8185                    .to_display_point(&snapshot);
 8186
 8187                breakpoint_display_points.insert(
 8188                    position.row(),
 8189                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8190                );
 8191            }
 8192        }
 8193
 8194        breakpoint_display_points
 8195    }
 8196
 8197    fn breakpoint_context_menu(
 8198        &self,
 8199        anchor: Anchor,
 8200        window: &mut Window,
 8201        cx: &mut Context<Self>,
 8202    ) -> Entity<ui::ContextMenu> {
 8203        let weak_editor = cx.weak_entity();
 8204        let focus_handle = self.focus_handle(cx);
 8205
 8206        let row = self
 8207            .buffer
 8208            .read(cx)
 8209            .snapshot(cx)
 8210            .summary_for_anchor::<Point>(&anchor)
 8211            .row;
 8212
 8213        let breakpoint = self
 8214            .breakpoint_at_row(row, window, cx)
 8215            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8216
 8217        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8218            "Edit Log Breakpoint"
 8219        } else {
 8220            "Set Log Breakpoint"
 8221        };
 8222
 8223        let condition_breakpoint_msg = if breakpoint
 8224            .as_ref()
 8225            .is_some_and(|bp| bp.1.condition.is_some())
 8226        {
 8227            "Edit Condition Breakpoint"
 8228        } else {
 8229            "Set Condition Breakpoint"
 8230        };
 8231
 8232        let hit_condition_breakpoint_msg = if breakpoint
 8233            .as_ref()
 8234            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8235        {
 8236            "Edit Hit Condition Breakpoint"
 8237        } else {
 8238            "Set Hit Condition Breakpoint"
 8239        };
 8240
 8241        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8242            "Unset Breakpoint"
 8243        } else {
 8244            "Set Breakpoint"
 8245        };
 8246
 8247        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8248
 8249        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8250            BreakpointState::Enabled => Some("Disable"),
 8251            BreakpointState::Disabled => Some("Enable"),
 8252        });
 8253
 8254        let (anchor, breakpoint) =
 8255            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8256
 8257        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8258            menu.on_blur_subscription(Subscription::new(|| {}))
 8259                .context(focus_handle)
 8260                .when(run_to_cursor, |this| {
 8261                    let weak_editor = weak_editor.clone();
 8262                    this.entry("Run to cursor", None, move |window, cx| {
 8263                        weak_editor
 8264                            .update(cx, |editor, cx| {
 8265                                editor.change_selections(
 8266                                    SelectionEffects::no_scroll(),
 8267                                    window,
 8268                                    cx,
 8269                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8270                                );
 8271                            })
 8272                            .ok();
 8273
 8274                        window.dispatch_action(Box::new(RunToCursor), cx);
 8275                    })
 8276                    .separator()
 8277                })
 8278                .when_some(toggle_state_msg, |this, msg| {
 8279                    this.entry(msg, None, {
 8280                        let weak_editor = weak_editor.clone();
 8281                        let breakpoint = breakpoint.clone();
 8282                        move |_window, cx| {
 8283                            weak_editor
 8284                                .update(cx, |this, cx| {
 8285                                    this.edit_breakpoint_at_anchor(
 8286                                        anchor,
 8287                                        breakpoint.as_ref().clone(),
 8288                                        BreakpointEditAction::InvertState,
 8289                                        cx,
 8290                                    );
 8291                                })
 8292                                .log_err();
 8293                        }
 8294                    })
 8295                })
 8296                .entry(set_breakpoint_msg, None, {
 8297                    let weak_editor = weak_editor.clone();
 8298                    let breakpoint = breakpoint.clone();
 8299                    move |_window, cx| {
 8300                        weak_editor
 8301                            .update(cx, |this, cx| {
 8302                                this.edit_breakpoint_at_anchor(
 8303                                    anchor,
 8304                                    breakpoint.as_ref().clone(),
 8305                                    BreakpointEditAction::Toggle,
 8306                                    cx,
 8307                                );
 8308                            })
 8309                            .log_err();
 8310                    }
 8311                })
 8312                .entry(log_breakpoint_msg, None, {
 8313                    let breakpoint = breakpoint.clone();
 8314                    let weak_editor = weak_editor.clone();
 8315                    move |window, cx| {
 8316                        weak_editor
 8317                            .update(cx, |this, cx| {
 8318                                this.add_edit_breakpoint_block(
 8319                                    anchor,
 8320                                    breakpoint.as_ref(),
 8321                                    BreakpointPromptEditAction::Log,
 8322                                    window,
 8323                                    cx,
 8324                                );
 8325                            })
 8326                            .log_err();
 8327                    }
 8328                })
 8329                .entry(condition_breakpoint_msg, None, {
 8330                    let breakpoint = breakpoint.clone();
 8331                    let weak_editor = weak_editor.clone();
 8332                    move |window, cx| {
 8333                        weak_editor
 8334                            .update(cx, |this, cx| {
 8335                                this.add_edit_breakpoint_block(
 8336                                    anchor,
 8337                                    breakpoint.as_ref(),
 8338                                    BreakpointPromptEditAction::Condition,
 8339                                    window,
 8340                                    cx,
 8341                                );
 8342                            })
 8343                            .log_err();
 8344                    }
 8345                })
 8346                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8347                    weak_editor
 8348                        .update(cx, |this, cx| {
 8349                            this.add_edit_breakpoint_block(
 8350                                anchor,
 8351                                breakpoint.as_ref(),
 8352                                BreakpointPromptEditAction::HitCondition,
 8353                                window,
 8354                                cx,
 8355                            );
 8356                        })
 8357                        .log_err();
 8358                })
 8359        })
 8360    }
 8361
 8362    fn render_breakpoint(
 8363        &self,
 8364        position: Anchor,
 8365        row: DisplayRow,
 8366        breakpoint: &Breakpoint,
 8367        state: Option<BreakpointSessionState>,
 8368        cx: &mut Context<Self>,
 8369    ) -> IconButton {
 8370        let is_rejected = state.is_some_and(|s| !s.verified);
 8371        // Is it a breakpoint that shows up when hovering over gutter?
 8372        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8373            (false, false),
 8374            |PhantomBreakpointIndicator {
 8375                 is_active,
 8376                 display_row,
 8377                 collides_with_existing_breakpoint,
 8378             }| {
 8379                (
 8380                    is_active && display_row == row,
 8381                    collides_with_existing_breakpoint,
 8382                )
 8383            },
 8384        );
 8385
 8386        let (color, icon) = {
 8387            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8388                (false, false) => ui::IconName::DebugBreakpoint,
 8389                (true, false) => ui::IconName::DebugLogBreakpoint,
 8390                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8391                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8392            };
 8393
 8394            let color = if is_phantom {
 8395                Color::Hint
 8396            } else if is_rejected {
 8397                Color::Disabled
 8398            } else {
 8399                Color::Debugger
 8400            };
 8401
 8402            (color, icon)
 8403        };
 8404
 8405        let breakpoint = Arc::from(breakpoint.clone());
 8406
 8407        let alt_as_text = gpui::Keystroke {
 8408            modifiers: Modifiers::secondary_key(),
 8409            ..Default::default()
 8410        };
 8411        let primary_action_text = if breakpoint.is_disabled() {
 8412            "Enable breakpoint"
 8413        } else if is_phantom && !collides_with_existing {
 8414            "Set breakpoint"
 8415        } else {
 8416            "Unset breakpoint"
 8417        };
 8418        let focus_handle = self.focus_handle.clone();
 8419
 8420        let meta = if is_rejected {
 8421            SharedString::from("No executable code is associated with this line.")
 8422        } else if collides_with_existing && !breakpoint.is_disabled() {
 8423            SharedString::from(format!(
 8424                "{alt_as_text}-click to disable,\nright-click for more options."
 8425            ))
 8426        } else {
 8427            SharedString::from("Right-click for more options.")
 8428        };
 8429        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8430            .icon_size(IconSize::XSmall)
 8431            .size(ui::ButtonSize::None)
 8432            .when(is_rejected, |this| {
 8433                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8434            })
 8435            .icon_color(color)
 8436            .style(ButtonStyle::Transparent)
 8437            .on_click(cx.listener({
 8438                move |editor, event: &ClickEvent, window, cx| {
 8439                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8440                        BreakpointEditAction::InvertState
 8441                    } else {
 8442                        BreakpointEditAction::Toggle
 8443                    };
 8444
 8445                    window.focus(&editor.focus_handle(cx));
 8446                    editor.edit_breakpoint_at_anchor(
 8447                        position,
 8448                        breakpoint.as_ref().clone(),
 8449                        edit_action,
 8450                        cx,
 8451                    );
 8452                }
 8453            }))
 8454            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8455                editor.set_breakpoint_context_menu(
 8456                    row,
 8457                    Some(position),
 8458                    event.position(),
 8459                    window,
 8460                    cx,
 8461                );
 8462            }))
 8463            .tooltip(move |_window, cx| {
 8464                Tooltip::with_meta_in(
 8465                    primary_action_text,
 8466                    Some(&ToggleBreakpoint),
 8467                    meta.clone(),
 8468                    &focus_handle,
 8469                    cx,
 8470                )
 8471            })
 8472    }
 8473
 8474    fn build_tasks_context(
 8475        project: &Entity<Project>,
 8476        buffer: &Entity<Buffer>,
 8477        buffer_row: u32,
 8478        tasks: &Arc<RunnableTasks>,
 8479        cx: &mut Context<Self>,
 8480    ) -> Task<Option<task::TaskContext>> {
 8481        let position = Point::new(buffer_row, tasks.column);
 8482        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8483        let location = Location {
 8484            buffer: buffer.clone(),
 8485            range: range_start..range_start,
 8486        };
 8487        // Fill in the environmental variables from the tree-sitter captures
 8488        let mut captured_task_variables = TaskVariables::default();
 8489        for (capture_name, value) in tasks.extra_variables.clone() {
 8490            captured_task_variables.insert(
 8491                task::VariableName::Custom(capture_name.into()),
 8492                value.clone(),
 8493            );
 8494        }
 8495        project.update(cx, |project, cx| {
 8496            project.task_store().update(cx, |task_store, cx| {
 8497                task_store.task_context_for_location(captured_task_variables, location, cx)
 8498            })
 8499        })
 8500    }
 8501
 8502    pub fn spawn_nearest_task(
 8503        &mut self,
 8504        action: &SpawnNearestTask,
 8505        window: &mut Window,
 8506        cx: &mut Context<Self>,
 8507    ) {
 8508        let Some((workspace, _)) = self.workspace.clone() else {
 8509            return;
 8510        };
 8511        let Some(project) = self.project.clone() else {
 8512            return;
 8513        };
 8514
 8515        // Try to find a closest, enclosing node using tree-sitter that has a task
 8516        let Some((buffer, buffer_row, tasks)) = self
 8517            .find_enclosing_node_task(cx)
 8518            // Or find the task that's closest in row-distance.
 8519            .or_else(|| self.find_closest_task(cx))
 8520        else {
 8521            return;
 8522        };
 8523
 8524        let reveal_strategy = action.reveal;
 8525        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8526        cx.spawn_in(window, async move |_, cx| {
 8527            let context = task_context.await?;
 8528            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8529
 8530            let resolved = &mut resolved_task.resolved;
 8531            resolved.reveal = reveal_strategy;
 8532
 8533            workspace
 8534                .update_in(cx, |workspace, window, cx| {
 8535                    workspace.schedule_resolved_task(
 8536                        task_source_kind,
 8537                        resolved_task,
 8538                        false,
 8539                        window,
 8540                        cx,
 8541                    );
 8542                })
 8543                .ok()
 8544        })
 8545        .detach();
 8546    }
 8547
 8548    fn find_closest_task(
 8549        &mut self,
 8550        cx: &mut Context<Self>,
 8551    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8552        let cursor_row = self
 8553            .selections
 8554            .newest_adjusted(&self.display_snapshot(cx))
 8555            .head()
 8556            .row;
 8557
 8558        let ((buffer_id, row), tasks) = self
 8559            .tasks
 8560            .iter()
 8561            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8562
 8563        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8564        let tasks = Arc::new(tasks.to_owned());
 8565        Some((buffer, *row, tasks))
 8566    }
 8567
 8568    fn find_enclosing_node_task(
 8569        &mut self,
 8570        cx: &mut Context<Self>,
 8571    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8572        let snapshot = self.buffer.read(cx).snapshot(cx);
 8573        let offset = self
 8574            .selections
 8575            .newest::<usize>(&self.display_snapshot(cx))
 8576            .head();
 8577        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8578        let buffer_id = excerpt.buffer().remote_id();
 8579
 8580        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8581        let mut cursor = layer.node().walk();
 8582
 8583        while cursor.goto_first_child_for_byte(offset).is_some() {
 8584            if cursor.node().end_byte() == offset {
 8585                cursor.goto_next_sibling();
 8586            }
 8587        }
 8588
 8589        // Ascend to the smallest ancestor that contains the range and has a task.
 8590        loop {
 8591            let node = cursor.node();
 8592            let node_range = node.byte_range();
 8593            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8594
 8595            // Check if this node contains our offset
 8596            if node_range.start <= offset && node_range.end >= offset {
 8597                // If it contains offset, check for task
 8598                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8599                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8600                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8601                }
 8602            }
 8603
 8604            if !cursor.goto_parent() {
 8605                break;
 8606            }
 8607        }
 8608        None
 8609    }
 8610
 8611    fn render_run_indicator(
 8612        &self,
 8613        _style: &EditorStyle,
 8614        is_active: bool,
 8615        row: DisplayRow,
 8616        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8617        cx: &mut Context<Self>,
 8618    ) -> IconButton {
 8619        let color = Color::Muted;
 8620        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8621
 8622        IconButton::new(
 8623            ("run_indicator", row.0 as usize),
 8624            ui::IconName::PlayOutlined,
 8625        )
 8626        .shape(ui::IconButtonShape::Square)
 8627        .icon_size(IconSize::XSmall)
 8628        .icon_color(color)
 8629        .toggle_state(is_active)
 8630        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8631            let quick_launch = match e {
 8632                ClickEvent::Keyboard(_) => true,
 8633                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8634            };
 8635
 8636            window.focus(&editor.focus_handle(cx));
 8637            editor.toggle_code_actions(
 8638                &ToggleCodeActions {
 8639                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8640                    quick_launch,
 8641                },
 8642                window,
 8643                cx,
 8644            );
 8645        }))
 8646        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8647            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8648        }))
 8649    }
 8650
 8651    pub fn context_menu_visible(&self) -> bool {
 8652        !self.edit_prediction_preview_is_active()
 8653            && self
 8654                .context_menu
 8655                .borrow()
 8656                .as_ref()
 8657                .is_some_and(|menu| menu.visible())
 8658    }
 8659
 8660    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8661        self.context_menu
 8662            .borrow()
 8663            .as_ref()
 8664            .map(|menu| menu.origin())
 8665    }
 8666
 8667    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8668        self.context_menu_options = Some(options);
 8669    }
 8670
 8671    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8672    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8673
 8674    fn render_edit_prediction_popover(
 8675        &mut self,
 8676        text_bounds: &Bounds<Pixels>,
 8677        content_origin: gpui::Point<Pixels>,
 8678        right_margin: Pixels,
 8679        editor_snapshot: &EditorSnapshot,
 8680        visible_row_range: Range<DisplayRow>,
 8681        scroll_top: ScrollOffset,
 8682        scroll_bottom: ScrollOffset,
 8683        line_layouts: &[LineWithInvisibles],
 8684        line_height: Pixels,
 8685        scroll_position: gpui::Point<ScrollOffset>,
 8686        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8687        newest_selection_head: Option<DisplayPoint>,
 8688        editor_width: Pixels,
 8689        style: &EditorStyle,
 8690        window: &mut Window,
 8691        cx: &mut App,
 8692    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8693        if self.mode().is_minimap() {
 8694            return None;
 8695        }
 8696        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8697
 8698        if self.edit_prediction_visible_in_cursor_popover(true) {
 8699            return None;
 8700        }
 8701
 8702        match &active_edit_prediction.completion {
 8703            EditPrediction::MoveWithin { target, .. } => {
 8704                let target_display_point = target.to_display_point(editor_snapshot);
 8705
 8706                if self.edit_prediction_requires_modifier() {
 8707                    if !self.edit_prediction_preview_is_active() {
 8708                        return None;
 8709                    }
 8710
 8711                    self.render_edit_prediction_modifier_jump_popover(
 8712                        text_bounds,
 8713                        content_origin,
 8714                        visible_row_range,
 8715                        line_layouts,
 8716                        line_height,
 8717                        scroll_pixel_position,
 8718                        newest_selection_head,
 8719                        target_display_point,
 8720                        window,
 8721                        cx,
 8722                    )
 8723                } else {
 8724                    self.render_edit_prediction_eager_jump_popover(
 8725                        text_bounds,
 8726                        content_origin,
 8727                        editor_snapshot,
 8728                        visible_row_range,
 8729                        scroll_top,
 8730                        scroll_bottom,
 8731                        line_height,
 8732                        scroll_pixel_position,
 8733                        target_display_point,
 8734                        editor_width,
 8735                        window,
 8736                        cx,
 8737                    )
 8738                }
 8739            }
 8740            EditPrediction::Edit {
 8741                display_mode: EditDisplayMode::Inline,
 8742                ..
 8743            } => None,
 8744            EditPrediction::Edit {
 8745                display_mode: EditDisplayMode::TabAccept,
 8746                edits,
 8747                ..
 8748            } => {
 8749                let range = &edits.first()?.0;
 8750                let target_display_point = range.end.to_display_point(editor_snapshot);
 8751
 8752                self.render_edit_prediction_end_of_line_popover(
 8753                    "Accept",
 8754                    editor_snapshot,
 8755                    visible_row_range,
 8756                    target_display_point,
 8757                    line_height,
 8758                    scroll_pixel_position,
 8759                    content_origin,
 8760                    editor_width,
 8761                    window,
 8762                    cx,
 8763                )
 8764            }
 8765            EditPrediction::Edit {
 8766                edits,
 8767                edit_preview,
 8768                display_mode: EditDisplayMode::DiffPopover,
 8769                snapshot,
 8770            } => self.render_edit_prediction_diff_popover(
 8771                text_bounds,
 8772                content_origin,
 8773                right_margin,
 8774                editor_snapshot,
 8775                visible_row_range,
 8776                line_layouts,
 8777                line_height,
 8778                scroll_position,
 8779                scroll_pixel_position,
 8780                newest_selection_head,
 8781                editor_width,
 8782                style,
 8783                edits,
 8784                edit_preview,
 8785                snapshot,
 8786                window,
 8787                cx,
 8788            ),
 8789            EditPrediction::MoveOutside { snapshot, .. } => {
 8790                let file_name = snapshot
 8791                    .file()
 8792                    .map(|file| file.file_name(cx))
 8793                    .unwrap_or("untitled");
 8794                let mut element = self
 8795                    .render_edit_prediction_line_popover(
 8796                        format!("Jump to {file_name}"),
 8797                        Some(IconName::ZedPredict),
 8798                        window,
 8799                        cx,
 8800                    )
 8801                    .into_any();
 8802
 8803                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8804                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8805                let origin_y = text_bounds.size.height - size.height - px(30.);
 8806                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8807                element.prepaint_at(origin, window, cx);
 8808
 8809                Some((element, origin))
 8810            }
 8811        }
 8812    }
 8813
 8814    fn render_edit_prediction_modifier_jump_popover(
 8815        &mut self,
 8816        text_bounds: &Bounds<Pixels>,
 8817        content_origin: gpui::Point<Pixels>,
 8818        visible_row_range: Range<DisplayRow>,
 8819        line_layouts: &[LineWithInvisibles],
 8820        line_height: Pixels,
 8821        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8822        newest_selection_head: Option<DisplayPoint>,
 8823        target_display_point: DisplayPoint,
 8824        window: &mut Window,
 8825        cx: &mut App,
 8826    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8827        let scrolled_content_origin =
 8828            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8829
 8830        const SCROLL_PADDING_Y: Pixels = px(12.);
 8831
 8832        if target_display_point.row() < visible_row_range.start {
 8833            return self.render_edit_prediction_scroll_popover(
 8834                |_| SCROLL_PADDING_Y,
 8835                IconName::ArrowUp,
 8836                visible_row_range,
 8837                line_layouts,
 8838                newest_selection_head,
 8839                scrolled_content_origin,
 8840                window,
 8841                cx,
 8842            );
 8843        } else if target_display_point.row() >= visible_row_range.end {
 8844            return self.render_edit_prediction_scroll_popover(
 8845                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8846                IconName::ArrowDown,
 8847                visible_row_range,
 8848                line_layouts,
 8849                newest_selection_head,
 8850                scrolled_content_origin,
 8851                window,
 8852                cx,
 8853            );
 8854        }
 8855
 8856        const POLE_WIDTH: Pixels = px(2.);
 8857
 8858        let line_layout =
 8859            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8860        let target_column = target_display_point.column() as usize;
 8861
 8862        let target_x = line_layout.x_for_index(target_column);
 8863        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8864            - scroll_pixel_position.y;
 8865
 8866        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8867
 8868        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8869        border_color.l += 0.001;
 8870
 8871        let mut element = v_flex()
 8872            .items_end()
 8873            .when(flag_on_right, |el| el.items_start())
 8874            .child(if flag_on_right {
 8875                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8876                    .rounded_bl(px(0.))
 8877                    .rounded_tl(px(0.))
 8878                    .border_l_2()
 8879                    .border_color(border_color)
 8880            } else {
 8881                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8882                    .rounded_br(px(0.))
 8883                    .rounded_tr(px(0.))
 8884                    .border_r_2()
 8885                    .border_color(border_color)
 8886            })
 8887            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8888            .into_any();
 8889
 8890        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8891
 8892        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8893            - point(
 8894                if flag_on_right {
 8895                    POLE_WIDTH
 8896                } else {
 8897                    size.width - POLE_WIDTH
 8898                },
 8899                size.height - line_height,
 8900            );
 8901
 8902        origin.x = origin.x.max(content_origin.x);
 8903
 8904        element.prepaint_at(origin, window, cx);
 8905
 8906        Some((element, origin))
 8907    }
 8908
 8909    fn render_edit_prediction_scroll_popover(
 8910        &mut self,
 8911        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8912        scroll_icon: IconName,
 8913        visible_row_range: Range<DisplayRow>,
 8914        line_layouts: &[LineWithInvisibles],
 8915        newest_selection_head: Option<DisplayPoint>,
 8916        scrolled_content_origin: gpui::Point<Pixels>,
 8917        window: &mut Window,
 8918        cx: &mut App,
 8919    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8920        let mut element = self
 8921            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8922            .into_any();
 8923
 8924        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8925
 8926        let cursor = newest_selection_head?;
 8927        let cursor_row_layout =
 8928            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8929        let cursor_column = cursor.column() as usize;
 8930
 8931        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8932
 8933        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8934
 8935        element.prepaint_at(origin, window, cx);
 8936        Some((element, origin))
 8937    }
 8938
 8939    fn render_edit_prediction_eager_jump_popover(
 8940        &mut self,
 8941        text_bounds: &Bounds<Pixels>,
 8942        content_origin: gpui::Point<Pixels>,
 8943        editor_snapshot: &EditorSnapshot,
 8944        visible_row_range: Range<DisplayRow>,
 8945        scroll_top: ScrollOffset,
 8946        scroll_bottom: ScrollOffset,
 8947        line_height: Pixels,
 8948        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8949        target_display_point: DisplayPoint,
 8950        editor_width: Pixels,
 8951        window: &mut Window,
 8952        cx: &mut App,
 8953    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8954        if target_display_point.row().as_f64() < scroll_top {
 8955            let mut element = self
 8956                .render_edit_prediction_line_popover(
 8957                    "Jump to Edit",
 8958                    Some(IconName::ArrowUp),
 8959                    window,
 8960                    cx,
 8961                )
 8962                .into_any();
 8963
 8964            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8965            let offset = point(
 8966                (text_bounds.size.width - size.width) / 2.,
 8967                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8968            );
 8969
 8970            let origin = text_bounds.origin + offset;
 8971            element.prepaint_at(origin, window, cx);
 8972            Some((element, origin))
 8973        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8974            let mut element = self
 8975                .render_edit_prediction_line_popover(
 8976                    "Jump to Edit",
 8977                    Some(IconName::ArrowDown),
 8978                    window,
 8979                    cx,
 8980                )
 8981                .into_any();
 8982
 8983            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8984            let offset = point(
 8985                (text_bounds.size.width - size.width) / 2.,
 8986                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8987            );
 8988
 8989            let origin = text_bounds.origin + offset;
 8990            element.prepaint_at(origin, window, cx);
 8991            Some((element, origin))
 8992        } else {
 8993            self.render_edit_prediction_end_of_line_popover(
 8994                "Jump to Edit",
 8995                editor_snapshot,
 8996                visible_row_range,
 8997                target_display_point,
 8998                line_height,
 8999                scroll_pixel_position,
 9000                content_origin,
 9001                editor_width,
 9002                window,
 9003                cx,
 9004            )
 9005        }
 9006    }
 9007
 9008    fn render_edit_prediction_end_of_line_popover(
 9009        self: &mut Editor,
 9010        label: &'static str,
 9011        editor_snapshot: &EditorSnapshot,
 9012        visible_row_range: Range<DisplayRow>,
 9013        target_display_point: DisplayPoint,
 9014        line_height: Pixels,
 9015        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9016        content_origin: gpui::Point<Pixels>,
 9017        editor_width: Pixels,
 9018        window: &mut Window,
 9019        cx: &mut App,
 9020    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9021        let target_line_end = DisplayPoint::new(
 9022            target_display_point.row(),
 9023            editor_snapshot.line_len(target_display_point.row()),
 9024        );
 9025
 9026        let mut element = self
 9027            .render_edit_prediction_line_popover(label, None, window, cx)
 9028            .into_any();
 9029
 9030        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9031
 9032        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9033
 9034        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9035        let mut origin = start_point
 9036            + line_origin
 9037            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9038        origin.x = origin.x.max(content_origin.x);
 9039
 9040        let max_x = content_origin.x + editor_width - size.width;
 9041
 9042        if origin.x > max_x {
 9043            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9044
 9045            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9046                origin.y += offset;
 9047                IconName::ArrowUp
 9048            } else {
 9049                origin.y -= offset;
 9050                IconName::ArrowDown
 9051            };
 9052
 9053            element = self
 9054                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9055                .into_any();
 9056
 9057            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9058
 9059            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9060        }
 9061
 9062        element.prepaint_at(origin, window, cx);
 9063        Some((element, origin))
 9064    }
 9065
 9066    fn render_edit_prediction_diff_popover(
 9067        self: &Editor,
 9068        text_bounds: &Bounds<Pixels>,
 9069        content_origin: gpui::Point<Pixels>,
 9070        right_margin: Pixels,
 9071        editor_snapshot: &EditorSnapshot,
 9072        visible_row_range: Range<DisplayRow>,
 9073        line_layouts: &[LineWithInvisibles],
 9074        line_height: Pixels,
 9075        scroll_position: gpui::Point<ScrollOffset>,
 9076        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9077        newest_selection_head: Option<DisplayPoint>,
 9078        editor_width: Pixels,
 9079        style: &EditorStyle,
 9080        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9081        edit_preview: &Option<language::EditPreview>,
 9082        snapshot: &language::BufferSnapshot,
 9083        window: &mut Window,
 9084        cx: &mut App,
 9085    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9086        let edit_start = edits
 9087            .first()
 9088            .unwrap()
 9089            .0
 9090            .start
 9091            .to_display_point(editor_snapshot);
 9092        let edit_end = edits
 9093            .last()
 9094            .unwrap()
 9095            .0
 9096            .end
 9097            .to_display_point(editor_snapshot);
 9098
 9099        let is_visible = visible_row_range.contains(&edit_start.row())
 9100            || visible_row_range.contains(&edit_end.row());
 9101        if !is_visible {
 9102            return None;
 9103        }
 9104
 9105        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9106            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9107        } else {
 9108            // Fallback for providers without edit_preview
 9109            crate::edit_prediction_fallback_text(edits, cx)
 9110        };
 9111
 9112        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9113        let line_count = highlighted_edits.text.lines().count();
 9114
 9115        const BORDER_WIDTH: Pixels = px(1.);
 9116
 9117        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9118        let has_keybind = keybind.is_some();
 9119
 9120        let mut element = h_flex()
 9121            .items_start()
 9122            .child(
 9123                h_flex()
 9124                    .bg(cx.theme().colors().editor_background)
 9125                    .border(BORDER_WIDTH)
 9126                    .shadow_xs()
 9127                    .border_color(cx.theme().colors().border)
 9128                    .rounded_l_lg()
 9129                    .when(line_count > 1, |el| el.rounded_br_lg())
 9130                    .pr_1()
 9131                    .child(styled_text),
 9132            )
 9133            .child(
 9134                h_flex()
 9135                    .h(line_height + BORDER_WIDTH * 2.)
 9136                    .px_1p5()
 9137                    .gap_1()
 9138                    // Workaround: For some reason, there's a gap if we don't do this
 9139                    .ml(-BORDER_WIDTH)
 9140                    .shadow(vec![gpui::BoxShadow {
 9141                        color: gpui::black().opacity(0.05),
 9142                        offset: point(px(1.), px(1.)),
 9143                        blur_radius: px(2.),
 9144                        spread_radius: px(0.),
 9145                    }])
 9146                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9147                    .border(BORDER_WIDTH)
 9148                    .border_color(cx.theme().colors().border)
 9149                    .rounded_r_lg()
 9150                    .id("edit_prediction_diff_popover_keybind")
 9151                    .when(!has_keybind, |el| {
 9152                        let status_colors = cx.theme().status();
 9153
 9154                        el.bg(status_colors.error_background)
 9155                            .border_color(status_colors.error.opacity(0.6))
 9156                            .child(Icon::new(IconName::Info).color(Color::Error))
 9157                            .cursor_default()
 9158                            .hoverable_tooltip(move |_window, cx| {
 9159                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9160                            })
 9161                    })
 9162                    .children(keybind),
 9163            )
 9164            .into_any();
 9165
 9166        let longest_row =
 9167            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9168        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9169            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9170        } else {
 9171            layout_line(
 9172                longest_row,
 9173                editor_snapshot,
 9174                style,
 9175                editor_width,
 9176                |_| false,
 9177                window,
 9178                cx,
 9179            )
 9180            .width
 9181        };
 9182
 9183        let viewport_bounds =
 9184            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9185                right: -right_margin,
 9186                ..Default::default()
 9187            });
 9188
 9189        let x_after_longest = Pixels::from(
 9190            ScrollPixelOffset::from(
 9191                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9192            ) - scroll_pixel_position.x,
 9193        );
 9194
 9195        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9196
 9197        // Fully visible if it can be displayed within the window (allow overlapping other
 9198        // panes). However, this is only allowed if the popover starts within text_bounds.
 9199        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9200            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9201
 9202        let mut origin = if can_position_to_the_right {
 9203            point(
 9204                x_after_longest,
 9205                text_bounds.origin.y
 9206                    + Pixels::from(
 9207                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9208                            - scroll_pixel_position.y,
 9209                    ),
 9210            )
 9211        } else {
 9212            let cursor_row = newest_selection_head.map(|head| head.row());
 9213            let above_edit = edit_start
 9214                .row()
 9215                .0
 9216                .checked_sub(line_count as u32)
 9217                .map(DisplayRow);
 9218            let below_edit = Some(edit_end.row() + 1);
 9219            let above_cursor =
 9220                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9221            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9222
 9223            // Place the edit popover adjacent to the edit if there is a location
 9224            // available that is onscreen and does not obscure the cursor. Otherwise,
 9225            // place it adjacent to the cursor.
 9226            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9227                .into_iter()
 9228                .flatten()
 9229                .find(|&start_row| {
 9230                    let end_row = start_row + line_count as u32;
 9231                    visible_row_range.contains(&start_row)
 9232                        && visible_row_range.contains(&end_row)
 9233                        && cursor_row
 9234                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9235                })?;
 9236
 9237            content_origin
 9238                + point(
 9239                    Pixels::from(-scroll_pixel_position.x),
 9240                    Pixels::from(
 9241                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9242                    ),
 9243                )
 9244        };
 9245
 9246        origin.x -= BORDER_WIDTH;
 9247
 9248        window.defer_draw(element, origin, 1);
 9249
 9250        // Do not return an element, since it will already be drawn due to defer_draw.
 9251        None
 9252    }
 9253
 9254    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9255        px(30.)
 9256    }
 9257
 9258    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9259        if self.read_only(cx) {
 9260            cx.theme().players().read_only()
 9261        } else {
 9262            self.style.as_ref().unwrap().local_player
 9263        }
 9264    }
 9265
 9266    fn render_edit_prediction_accept_keybind(
 9267        &self,
 9268        window: &mut Window,
 9269        cx: &mut App,
 9270    ) -> Option<AnyElement> {
 9271        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9272        let accept_keystroke = accept_binding.keystroke()?;
 9273
 9274        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9275
 9276        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9277            Color::Accent
 9278        } else {
 9279            Color::Muted
 9280        };
 9281
 9282        h_flex()
 9283            .px_0p5()
 9284            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9285            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9286            .text_size(TextSize::XSmall.rems(cx))
 9287            .child(h_flex().children(ui::render_modifiers(
 9288                accept_keystroke.modifiers(),
 9289                PlatformStyle::platform(),
 9290                Some(modifiers_color),
 9291                Some(IconSize::XSmall.rems().into()),
 9292                true,
 9293            )))
 9294            .when(is_platform_style_mac, |parent| {
 9295                parent.child(accept_keystroke.key().to_string())
 9296            })
 9297            .when(!is_platform_style_mac, |parent| {
 9298                parent.child(
 9299                    Key::new(
 9300                        util::capitalize(accept_keystroke.key()),
 9301                        Some(Color::Default),
 9302                    )
 9303                    .size(Some(IconSize::XSmall.rems().into())),
 9304                )
 9305            })
 9306            .into_any()
 9307            .into()
 9308    }
 9309
 9310    fn render_edit_prediction_line_popover(
 9311        &self,
 9312        label: impl Into<SharedString>,
 9313        icon: Option<IconName>,
 9314        window: &mut Window,
 9315        cx: &mut App,
 9316    ) -> Stateful<Div> {
 9317        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9318
 9319        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9320        let has_keybind = keybind.is_some();
 9321
 9322        h_flex()
 9323            .id("ep-line-popover")
 9324            .py_0p5()
 9325            .pl_1()
 9326            .pr(padding_right)
 9327            .gap_1()
 9328            .rounded_md()
 9329            .border_1()
 9330            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9331            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9332            .shadow_xs()
 9333            .when(!has_keybind, |el| {
 9334                let status_colors = cx.theme().status();
 9335
 9336                el.bg(status_colors.error_background)
 9337                    .border_color(status_colors.error.opacity(0.6))
 9338                    .pl_2()
 9339                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9340                    .cursor_default()
 9341                    .hoverable_tooltip(move |_window, cx| {
 9342                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9343                    })
 9344            })
 9345            .children(keybind)
 9346            .child(
 9347                Label::new(label)
 9348                    .size(LabelSize::Small)
 9349                    .when(!has_keybind, |el| {
 9350                        el.color(cx.theme().status().error.into()).strikethrough()
 9351                    }),
 9352            )
 9353            .when(!has_keybind, |el| {
 9354                el.child(
 9355                    h_flex().ml_1().child(
 9356                        Icon::new(IconName::Info)
 9357                            .size(IconSize::Small)
 9358                            .color(cx.theme().status().error.into()),
 9359                    ),
 9360                )
 9361            })
 9362            .when_some(icon, |element, icon| {
 9363                element.child(
 9364                    div()
 9365                        .mt(px(1.5))
 9366                        .child(Icon::new(icon).size(IconSize::Small)),
 9367                )
 9368            })
 9369    }
 9370
 9371    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9372        let accent_color = cx.theme().colors().text_accent;
 9373        let editor_bg_color = cx.theme().colors().editor_background;
 9374        editor_bg_color.blend(accent_color.opacity(0.1))
 9375    }
 9376
 9377    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9378        let accent_color = cx.theme().colors().text_accent;
 9379        let editor_bg_color = cx.theme().colors().editor_background;
 9380        editor_bg_color.blend(accent_color.opacity(0.6))
 9381    }
 9382    fn get_prediction_provider_icon_name(
 9383        provider: &Option<RegisteredEditPredictionProvider>,
 9384    ) -> IconName {
 9385        match provider {
 9386            Some(provider) => match provider.provider.name() {
 9387                "copilot" => IconName::Copilot,
 9388                "supermaven" => IconName::Supermaven,
 9389                _ => IconName::ZedPredict,
 9390            },
 9391            None => IconName::ZedPredict,
 9392        }
 9393    }
 9394
 9395    fn render_edit_prediction_cursor_popover(
 9396        &self,
 9397        min_width: Pixels,
 9398        max_width: Pixels,
 9399        cursor_point: Point,
 9400        style: &EditorStyle,
 9401        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9402        _window: &Window,
 9403        cx: &mut Context<Editor>,
 9404    ) -> Option<AnyElement> {
 9405        let provider = self.edit_prediction_provider.as_ref()?;
 9406        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9407
 9408        let is_refreshing = provider.provider.is_refreshing(cx);
 9409
 9410        fn pending_completion_container(icon: IconName) -> Div {
 9411            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9412        }
 9413
 9414        let completion = match &self.active_edit_prediction {
 9415            Some(prediction) => {
 9416                if !self.has_visible_completions_menu() {
 9417                    const RADIUS: Pixels = px(6.);
 9418                    const BORDER_WIDTH: Pixels = px(1.);
 9419
 9420                    return Some(
 9421                        h_flex()
 9422                            .elevation_2(cx)
 9423                            .border(BORDER_WIDTH)
 9424                            .border_color(cx.theme().colors().border)
 9425                            .when(accept_keystroke.is_none(), |el| {
 9426                                el.border_color(cx.theme().status().error)
 9427                            })
 9428                            .rounded(RADIUS)
 9429                            .rounded_tl(px(0.))
 9430                            .overflow_hidden()
 9431                            .child(div().px_1p5().child(match &prediction.completion {
 9432                                EditPrediction::MoveWithin { target, snapshot } => {
 9433                                    use text::ToPoint as _;
 9434                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9435                                    {
 9436                                        Icon::new(IconName::ZedPredictDown)
 9437                                    } else {
 9438                                        Icon::new(IconName::ZedPredictUp)
 9439                                    }
 9440                                }
 9441                                EditPrediction::MoveOutside { .. } => {
 9442                                    // TODO [zeta2] custom icon for external jump?
 9443                                    Icon::new(provider_icon)
 9444                                }
 9445                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9446                            }))
 9447                            .child(
 9448                                h_flex()
 9449                                    .gap_1()
 9450                                    .py_1()
 9451                                    .px_2()
 9452                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9453                                    .border_l_1()
 9454                                    .border_color(cx.theme().colors().border)
 9455                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9456                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9457                                        el.child(
 9458                                            Label::new("Hold")
 9459                                                .size(LabelSize::Small)
 9460                                                .when(accept_keystroke.is_none(), |el| {
 9461                                                    el.strikethrough()
 9462                                                })
 9463                                                .line_height_style(LineHeightStyle::UiLabel),
 9464                                        )
 9465                                    })
 9466                                    .id("edit_prediction_cursor_popover_keybind")
 9467                                    .when(accept_keystroke.is_none(), |el| {
 9468                                        let status_colors = cx.theme().status();
 9469
 9470                                        el.bg(status_colors.error_background)
 9471                                            .border_color(status_colors.error.opacity(0.6))
 9472                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9473                                            .cursor_default()
 9474                                            .hoverable_tooltip(move |_window, cx| {
 9475                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9476                                                    .into()
 9477                                            })
 9478                                    })
 9479                                    .when_some(
 9480                                        accept_keystroke.as_ref(),
 9481                                        |el, accept_keystroke| {
 9482                                            el.child(h_flex().children(ui::render_modifiers(
 9483                                                accept_keystroke.modifiers(),
 9484                                                PlatformStyle::platform(),
 9485                                                Some(Color::Default),
 9486                                                Some(IconSize::XSmall.rems().into()),
 9487                                                false,
 9488                                            )))
 9489                                        },
 9490                                    ),
 9491                            )
 9492                            .into_any(),
 9493                    );
 9494                }
 9495
 9496                self.render_edit_prediction_cursor_popover_preview(
 9497                    prediction,
 9498                    cursor_point,
 9499                    style,
 9500                    cx,
 9501                )?
 9502            }
 9503
 9504            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9505                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9506                    stale_completion,
 9507                    cursor_point,
 9508                    style,
 9509                    cx,
 9510                )?,
 9511
 9512                None => pending_completion_container(provider_icon)
 9513                    .child(Label::new("...").size(LabelSize::Small)),
 9514            },
 9515
 9516            None => pending_completion_container(provider_icon)
 9517                .child(Label::new("...").size(LabelSize::Small)),
 9518        };
 9519
 9520        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9521            completion
 9522                .with_animation(
 9523                    "loading-completion",
 9524                    Animation::new(Duration::from_secs(2))
 9525                        .repeat()
 9526                        .with_easing(pulsating_between(0.4, 0.8)),
 9527                    |label, delta| label.opacity(delta),
 9528                )
 9529                .into_any_element()
 9530        } else {
 9531            completion.into_any_element()
 9532        };
 9533
 9534        let has_completion = self.active_edit_prediction.is_some();
 9535
 9536        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9537        Some(
 9538            h_flex()
 9539                .min_w(min_width)
 9540                .max_w(max_width)
 9541                .flex_1()
 9542                .elevation_2(cx)
 9543                .border_color(cx.theme().colors().border)
 9544                .child(
 9545                    div()
 9546                        .flex_1()
 9547                        .py_1()
 9548                        .px_2()
 9549                        .overflow_hidden()
 9550                        .child(completion),
 9551                )
 9552                .when_some(accept_keystroke, |el, accept_keystroke| {
 9553                    if !accept_keystroke.modifiers().modified() {
 9554                        return el;
 9555                    }
 9556
 9557                    el.child(
 9558                        h_flex()
 9559                            .h_full()
 9560                            .border_l_1()
 9561                            .rounded_r_lg()
 9562                            .border_color(cx.theme().colors().border)
 9563                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9564                            .gap_1()
 9565                            .py_1()
 9566                            .px_2()
 9567                            .child(
 9568                                h_flex()
 9569                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9570                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9571                                    .child(h_flex().children(ui::render_modifiers(
 9572                                        accept_keystroke.modifiers(),
 9573                                        PlatformStyle::platform(),
 9574                                        Some(if !has_completion {
 9575                                            Color::Muted
 9576                                        } else {
 9577                                            Color::Default
 9578                                        }),
 9579                                        None,
 9580                                        false,
 9581                                    ))),
 9582                            )
 9583                            .child(Label::new("Preview").into_any_element())
 9584                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9585                    )
 9586                })
 9587                .into_any(),
 9588        )
 9589    }
 9590
 9591    fn render_edit_prediction_cursor_popover_preview(
 9592        &self,
 9593        completion: &EditPredictionState,
 9594        cursor_point: Point,
 9595        style: &EditorStyle,
 9596        cx: &mut Context<Editor>,
 9597    ) -> Option<Div> {
 9598        use text::ToPoint as _;
 9599
 9600        fn render_relative_row_jump(
 9601            prefix: impl Into<String>,
 9602            current_row: u32,
 9603            target_row: u32,
 9604        ) -> Div {
 9605            let (row_diff, arrow) = if target_row < current_row {
 9606                (current_row - target_row, IconName::ArrowUp)
 9607            } else {
 9608                (target_row - current_row, IconName::ArrowDown)
 9609            };
 9610
 9611            h_flex()
 9612                .child(
 9613                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9614                        .color(Color::Muted)
 9615                        .size(LabelSize::Small),
 9616                )
 9617                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9618        }
 9619
 9620        let supports_jump = self
 9621            .edit_prediction_provider
 9622            .as_ref()
 9623            .map(|provider| provider.provider.supports_jump_to_edit())
 9624            .unwrap_or(true);
 9625
 9626        match &completion.completion {
 9627            EditPrediction::MoveWithin {
 9628                target, snapshot, ..
 9629            } => {
 9630                if !supports_jump {
 9631                    return None;
 9632                }
 9633
 9634                Some(
 9635                    h_flex()
 9636                        .px_2()
 9637                        .gap_2()
 9638                        .flex_1()
 9639                        .child(
 9640                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9641                                Icon::new(IconName::ZedPredictDown)
 9642                            } else {
 9643                                Icon::new(IconName::ZedPredictUp)
 9644                            },
 9645                        )
 9646                        .child(Label::new("Jump to Edit")),
 9647                )
 9648            }
 9649            EditPrediction::MoveOutside { snapshot, .. } => {
 9650                let file_name = snapshot
 9651                    .file()
 9652                    .map(|file| file.file_name(cx))
 9653                    .unwrap_or("untitled");
 9654                Some(
 9655                    h_flex()
 9656                        .px_2()
 9657                        .gap_2()
 9658                        .flex_1()
 9659                        .child(Icon::new(IconName::ZedPredict))
 9660                        .child(Label::new(format!("Jump to {file_name}"))),
 9661                )
 9662            }
 9663            EditPrediction::Edit {
 9664                edits,
 9665                edit_preview,
 9666                snapshot,
 9667                display_mode: _,
 9668            } => {
 9669                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9670
 9671                let (highlighted_edits, has_more_lines) =
 9672                    if let Some(edit_preview) = edit_preview.as_ref() {
 9673                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9674                            .first_line_preview()
 9675                    } else {
 9676                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9677                    };
 9678
 9679                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9680                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9681
 9682                let preview = h_flex()
 9683                    .gap_1()
 9684                    .min_w_16()
 9685                    .child(styled_text)
 9686                    .when(has_more_lines, |parent| parent.child(""));
 9687
 9688                let left = if supports_jump && first_edit_row != cursor_point.row {
 9689                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9690                        .into_any_element()
 9691                } else {
 9692                    let icon_name =
 9693                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9694                    Icon::new(icon_name).into_any_element()
 9695                };
 9696
 9697                Some(
 9698                    h_flex()
 9699                        .h_full()
 9700                        .flex_1()
 9701                        .gap_2()
 9702                        .pr_1()
 9703                        .overflow_x_hidden()
 9704                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9705                        .child(left)
 9706                        .child(preview),
 9707                )
 9708            }
 9709        }
 9710    }
 9711
 9712    pub fn render_context_menu(
 9713        &self,
 9714        style: &EditorStyle,
 9715        max_height_in_lines: u32,
 9716        window: &mut Window,
 9717        cx: &mut Context<Editor>,
 9718    ) -> Option<AnyElement> {
 9719        let menu = self.context_menu.borrow();
 9720        let menu = menu.as_ref()?;
 9721        if !menu.visible() {
 9722            return None;
 9723        };
 9724        Some(menu.render(style, max_height_in_lines, window, cx))
 9725    }
 9726
 9727    fn render_context_menu_aside(
 9728        &mut self,
 9729        max_size: Size<Pixels>,
 9730        window: &mut Window,
 9731        cx: &mut Context<Editor>,
 9732    ) -> Option<AnyElement> {
 9733        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9734            if menu.visible() {
 9735                menu.render_aside(max_size, window, cx)
 9736            } else {
 9737                None
 9738            }
 9739        })
 9740    }
 9741
 9742    fn hide_context_menu(
 9743        &mut self,
 9744        window: &mut Window,
 9745        cx: &mut Context<Self>,
 9746    ) -> Option<CodeContextMenu> {
 9747        cx.notify();
 9748        self.completion_tasks.clear();
 9749        let context_menu = self.context_menu.borrow_mut().take();
 9750        self.stale_edit_prediction_in_menu.take();
 9751        self.update_visible_edit_prediction(window, cx);
 9752        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9753            && let Some(completion_provider) = &self.completion_provider
 9754        {
 9755            completion_provider.selection_changed(None, window, cx);
 9756        }
 9757        context_menu
 9758    }
 9759
 9760    fn show_snippet_choices(
 9761        &mut self,
 9762        choices: &Vec<String>,
 9763        selection: Range<Anchor>,
 9764        cx: &mut Context<Self>,
 9765    ) {
 9766        let Some((_, buffer, _)) = self
 9767            .buffer()
 9768            .read(cx)
 9769            .excerpt_containing(selection.start, cx)
 9770        else {
 9771            return;
 9772        };
 9773        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9774        else {
 9775            return;
 9776        };
 9777        if buffer != end_buffer {
 9778            log::error!("expected anchor range to have matching buffer IDs");
 9779            return;
 9780        }
 9781
 9782        let id = post_inc(&mut self.next_completion_id);
 9783        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9784        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9785            CompletionsMenu::new_snippet_choices(
 9786                id,
 9787                true,
 9788                choices,
 9789                selection,
 9790                buffer,
 9791                snippet_sort_order,
 9792            ),
 9793        ));
 9794    }
 9795
 9796    pub fn insert_snippet(
 9797        &mut self,
 9798        insertion_ranges: &[Range<usize>],
 9799        snippet: Snippet,
 9800        window: &mut Window,
 9801        cx: &mut Context<Self>,
 9802    ) -> Result<()> {
 9803        struct Tabstop<T> {
 9804            is_end_tabstop: bool,
 9805            ranges: Vec<Range<T>>,
 9806            choices: Option<Vec<String>>,
 9807        }
 9808
 9809        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9810            let snippet_text: Arc<str> = snippet.text.clone().into();
 9811            let edits = insertion_ranges
 9812                .iter()
 9813                .cloned()
 9814                .map(|range| (range, snippet_text.clone()));
 9815            let autoindent_mode = AutoindentMode::Block {
 9816                original_indent_columns: Vec::new(),
 9817            };
 9818            buffer.edit(edits, Some(autoindent_mode), cx);
 9819
 9820            let snapshot = &*buffer.read(cx);
 9821            let snippet = &snippet;
 9822            snippet
 9823                .tabstops
 9824                .iter()
 9825                .map(|tabstop| {
 9826                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9827                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9828                    });
 9829                    let mut tabstop_ranges = tabstop
 9830                        .ranges
 9831                        .iter()
 9832                        .flat_map(|tabstop_range| {
 9833                            let mut delta = 0_isize;
 9834                            insertion_ranges.iter().map(move |insertion_range| {
 9835                                let insertion_start = insertion_range.start as isize + delta;
 9836                                delta +=
 9837                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9838
 9839                                let start = ((insertion_start + tabstop_range.start) as usize)
 9840                                    .min(snapshot.len());
 9841                                let end = ((insertion_start + tabstop_range.end) as usize)
 9842                                    .min(snapshot.len());
 9843                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9844                            })
 9845                        })
 9846                        .collect::<Vec<_>>();
 9847                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9848
 9849                    Tabstop {
 9850                        is_end_tabstop,
 9851                        ranges: tabstop_ranges,
 9852                        choices: tabstop.choices.clone(),
 9853                    }
 9854                })
 9855                .collect::<Vec<_>>()
 9856        });
 9857        if let Some(tabstop) = tabstops.first() {
 9858            self.change_selections(Default::default(), window, cx, |s| {
 9859                // Reverse order so that the first range is the newest created selection.
 9860                // Completions will use it and autoscroll will prioritize it.
 9861                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9862            });
 9863
 9864            if let Some(choices) = &tabstop.choices
 9865                && let Some(selection) = tabstop.ranges.first()
 9866            {
 9867                self.show_snippet_choices(choices, selection.clone(), cx)
 9868            }
 9869
 9870            // If we're already at the last tabstop and it's at the end of the snippet,
 9871            // we're done, we don't need to keep the state around.
 9872            if !tabstop.is_end_tabstop {
 9873                let choices = tabstops
 9874                    .iter()
 9875                    .map(|tabstop| tabstop.choices.clone())
 9876                    .collect();
 9877
 9878                let ranges = tabstops
 9879                    .into_iter()
 9880                    .map(|tabstop| tabstop.ranges)
 9881                    .collect::<Vec<_>>();
 9882
 9883                self.snippet_stack.push(SnippetState {
 9884                    active_index: 0,
 9885                    ranges,
 9886                    choices,
 9887                });
 9888            }
 9889
 9890            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9891            if self.autoclose_regions.is_empty() {
 9892                let snapshot = self.buffer.read(cx).snapshot(cx);
 9893                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9894                    let selection_head = selection.head();
 9895                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9896                        continue;
 9897                    };
 9898
 9899                    let mut bracket_pair = None;
 9900                    let max_lookup_length = scope
 9901                        .brackets()
 9902                        .map(|(pair, _)| {
 9903                            pair.start
 9904                                .as_str()
 9905                                .chars()
 9906                                .count()
 9907                                .max(pair.end.as_str().chars().count())
 9908                        })
 9909                        .max();
 9910                    if let Some(max_lookup_length) = max_lookup_length {
 9911                        let next_text = snapshot
 9912                            .chars_at(selection_head)
 9913                            .take(max_lookup_length)
 9914                            .collect::<String>();
 9915                        let prev_text = snapshot
 9916                            .reversed_chars_at(selection_head)
 9917                            .take(max_lookup_length)
 9918                            .collect::<String>();
 9919
 9920                        for (pair, enabled) in scope.brackets() {
 9921                            if enabled
 9922                                && pair.close
 9923                                && prev_text.starts_with(pair.start.as_str())
 9924                                && next_text.starts_with(pair.end.as_str())
 9925                            {
 9926                                bracket_pair = Some(pair.clone());
 9927                                break;
 9928                            }
 9929                        }
 9930                    }
 9931
 9932                    if let Some(pair) = bracket_pair {
 9933                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9934                        let autoclose_enabled =
 9935                            self.use_autoclose && snapshot_settings.use_autoclose;
 9936                        if autoclose_enabled {
 9937                            let start = snapshot.anchor_after(selection_head);
 9938                            let end = snapshot.anchor_after(selection_head);
 9939                            self.autoclose_regions.push(AutocloseRegion {
 9940                                selection_id: selection.id,
 9941                                range: start..end,
 9942                                pair,
 9943                            });
 9944                        }
 9945                    }
 9946                }
 9947            }
 9948        }
 9949        Ok(())
 9950    }
 9951
 9952    pub fn move_to_next_snippet_tabstop(
 9953        &mut self,
 9954        window: &mut Window,
 9955        cx: &mut Context<Self>,
 9956    ) -> bool {
 9957        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9958    }
 9959
 9960    pub fn move_to_prev_snippet_tabstop(
 9961        &mut self,
 9962        window: &mut Window,
 9963        cx: &mut Context<Self>,
 9964    ) -> bool {
 9965        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9966    }
 9967
 9968    pub fn move_to_snippet_tabstop(
 9969        &mut self,
 9970        bias: Bias,
 9971        window: &mut Window,
 9972        cx: &mut Context<Self>,
 9973    ) -> bool {
 9974        if let Some(mut snippet) = self.snippet_stack.pop() {
 9975            match bias {
 9976                Bias::Left => {
 9977                    if snippet.active_index > 0 {
 9978                        snippet.active_index -= 1;
 9979                    } else {
 9980                        self.snippet_stack.push(snippet);
 9981                        return false;
 9982                    }
 9983                }
 9984                Bias::Right => {
 9985                    if snippet.active_index + 1 < snippet.ranges.len() {
 9986                        snippet.active_index += 1;
 9987                    } else {
 9988                        self.snippet_stack.push(snippet);
 9989                        return false;
 9990                    }
 9991                }
 9992            }
 9993            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9994                self.change_selections(Default::default(), window, cx, |s| {
 9995                    // Reverse order so that the first range is the newest created selection.
 9996                    // Completions will use it and autoscroll will prioritize it.
 9997                    s.select_ranges(current_ranges.iter().rev().cloned())
 9998                });
 9999
10000                if let Some(choices) = &snippet.choices[snippet.active_index]
10001                    && let Some(selection) = current_ranges.first()
10002                {
10003                    self.show_snippet_choices(choices, selection.clone(), cx);
10004                }
10005
10006                // If snippet state is not at the last tabstop, push it back on the stack
10007                if snippet.active_index + 1 < snippet.ranges.len() {
10008                    self.snippet_stack.push(snippet);
10009                }
10010                return true;
10011            }
10012        }
10013
10014        false
10015    }
10016
10017    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10018        self.transact(window, cx, |this, window, cx| {
10019            this.select_all(&SelectAll, window, cx);
10020            this.insert("", window, cx);
10021        });
10022    }
10023
10024    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10025        if self.read_only(cx) {
10026            return;
10027        }
10028        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10029        self.transact(window, cx, |this, window, cx| {
10030            this.select_autoclose_pair(window, cx);
10031
10032            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10033
10034            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10035            if !this.linked_edit_ranges.is_empty() {
10036                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10037                let snapshot = this.buffer.read(cx).snapshot(cx);
10038
10039                for selection in selections.iter() {
10040                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10041                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10042                    if selection_start.buffer_id != selection_end.buffer_id {
10043                        continue;
10044                    }
10045                    if let Some(ranges) =
10046                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10047                    {
10048                        for (buffer, entries) in ranges {
10049                            linked_ranges.entry(buffer).or_default().extend(entries);
10050                        }
10051                    }
10052                }
10053            }
10054
10055            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10056            for selection in &mut selections {
10057                if selection.is_empty() {
10058                    let old_head = selection.head();
10059                    let mut new_head =
10060                        movement::left(&display_map, old_head.to_display_point(&display_map))
10061                            .to_point(&display_map);
10062                    if let Some((buffer, line_buffer_range)) = display_map
10063                        .buffer_snapshot()
10064                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10065                    {
10066                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10067                        let indent_len = match indent_size.kind {
10068                            IndentKind::Space => {
10069                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10070                            }
10071                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10072                        };
10073                        if old_head.column <= indent_size.len && old_head.column > 0 {
10074                            let indent_len = indent_len.get();
10075                            new_head = cmp::min(
10076                                new_head,
10077                                MultiBufferPoint::new(
10078                                    old_head.row,
10079                                    ((old_head.column - 1) / indent_len) * indent_len,
10080                                ),
10081                            );
10082                        }
10083                    }
10084
10085                    selection.set_head(new_head, SelectionGoal::None);
10086                }
10087            }
10088
10089            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10090            this.insert("", window, cx);
10091            let empty_str: Arc<str> = Arc::from("");
10092            for (buffer, edits) in linked_ranges {
10093                let snapshot = buffer.read(cx).snapshot();
10094                use text::ToPoint as TP;
10095
10096                let edits = edits
10097                    .into_iter()
10098                    .map(|range| {
10099                        let end_point = TP::to_point(&range.end, &snapshot);
10100                        let mut start_point = TP::to_point(&range.start, &snapshot);
10101
10102                        if end_point == start_point {
10103                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10104                                .saturating_sub(1);
10105                            start_point =
10106                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10107                        };
10108
10109                        (start_point..end_point, empty_str.clone())
10110                    })
10111                    .sorted_by_key(|(range, _)| range.start)
10112                    .collect::<Vec<_>>();
10113                buffer.update(cx, |this, cx| {
10114                    this.edit(edits, None, cx);
10115                })
10116            }
10117            this.refresh_edit_prediction(true, false, window, cx);
10118            refresh_linked_ranges(this, window, cx);
10119        });
10120    }
10121
10122    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10123        if self.read_only(cx) {
10124            return;
10125        }
10126        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10127        self.transact(window, cx, |this, window, cx| {
10128            this.change_selections(Default::default(), window, cx, |s| {
10129                s.move_with(|map, selection| {
10130                    if selection.is_empty() {
10131                        let cursor = movement::right(map, selection.head());
10132                        selection.end = cursor;
10133                        selection.reversed = true;
10134                        selection.goal = SelectionGoal::None;
10135                    }
10136                })
10137            });
10138            this.insert("", window, cx);
10139            this.refresh_edit_prediction(true, false, window, cx);
10140        });
10141    }
10142
10143    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10144        if self.mode.is_single_line() {
10145            cx.propagate();
10146            return;
10147        }
10148
10149        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10150        if self.move_to_prev_snippet_tabstop(window, cx) {
10151            return;
10152        }
10153        self.outdent(&Outdent, window, cx);
10154    }
10155
10156    pub fn next_snippet_tabstop(
10157        &mut self,
10158        _: &NextSnippetTabstop,
10159        window: &mut Window,
10160        cx: &mut Context<Self>,
10161    ) {
10162        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10163            cx.propagate();
10164            return;
10165        }
10166
10167        if self.move_to_next_snippet_tabstop(window, cx) {
10168            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10169            return;
10170        }
10171        cx.propagate();
10172    }
10173
10174    pub fn previous_snippet_tabstop(
10175        &mut self,
10176        _: &PreviousSnippetTabstop,
10177        window: &mut Window,
10178        cx: &mut Context<Self>,
10179    ) {
10180        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10181            cx.propagate();
10182            return;
10183        }
10184
10185        if self.move_to_prev_snippet_tabstop(window, cx) {
10186            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10187            return;
10188        }
10189        cx.propagate();
10190    }
10191
10192    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10193        if self.mode.is_single_line() {
10194            cx.propagate();
10195            return;
10196        }
10197
10198        if self.move_to_next_snippet_tabstop(window, cx) {
10199            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10200            return;
10201        }
10202        if self.read_only(cx) {
10203            return;
10204        }
10205        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10206        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10207        let buffer = self.buffer.read(cx);
10208        let snapshot = buffer.snapshot(cx);
10209        let rows_iter = selections.iter().map(|s| s.head().row);
10210        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10211
10212        let has_some_cursor_in_whitespace = selections
10213            .iter()
10214            .filter(|selection| selection.is_empty())
10215            .any(|selection| {
10216                let cursor = selection.head();
10217                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10218                cursor.column < current_indent.len
10219            });
10220
10221        let mut edits = Vec::new();
10222        let mut prev_edited_row = 0;
10223        let mut row_delta = 0;
10224        for selection in &mut selections {
10225            if selection.start.row != prev_edited_row {
10226                row_delta = 0;
10227            }
10228            prev_edited_row = selection.end.row;
10229
10230            // If the selection is non-empty, then increase the indentation of the selected lines.
10231            if !selection.is_empty() {
10232                row_delta =
10233                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10234                continue;
10235            }
10236
10237            let cursor = selection.head();
10238            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10239            if let Some(suggested_indent) =
10240                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10241            {
10242                // Don't do anything if already at suggested indent
10243                // and there is any other cursor which is not
10244                if has_some_cursor_in_whitespace
10245                    && cursor.column == current_indent.len
10246                    && current_indent.len == suggested_indent.len
10247                {
10248                    continue;
10249                }
10250
10251                // Adjust line and move cursor to suggested indent
10252                // if cursor is not at suggested indent
10253                if cursor.column < suggested_indent.len
10254                    && cursor.column <= current_indent.len
10255                    && current_indent.len <= suggested_indent.len
10256                {
10257                    selection.start = Point::new(cursor.row, suggested_indent.len);
10258                    selection.end = selection.start;
10259                    if row_delta == 0 {
10260                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10261                            cursor.row,
10262                            current_indent,
10263                            suggested_indent,
10264                        ));
10265                        row_delta = suggested_indent.len - current_indent.len;
10266                    }
10267                    continue;
10268                }
10269
10270                // If current indent is more than suggested indent
10271                // only move cursor to current indent and skip indent
10272                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10273                    selection.start = Point::new(cursor.row, current_indent.len);
10274                    selection.end = selection.start;
10275                    continue;
10276                }
10277            }
10278
10279            // Otherwise, insert a hard or soft tab.
10280            let settings = buffer.language_settings_at(cursor, cx);
10281            let tab_size = if settings.hard_tabs {
10282                IndentSize::tab()
10283            } else {
10284                let tab_size = settings.tab_size.get();
10285                let indent_remainder = snapshot
10286                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10287                    .flat_map(str::chars)
10288                    .fold(row_delta % tab_size, |counter: u32, c| {
10289                        if c == '\t' {
10290                            0
10291                        } else {
10292                            (counter + 1) % tab_size
10293                        }
10294                    });
10295
10296                let chars_to_next_tab_stop = tab_size - indent_remainder;
10297                IndentSize::spaces(chars_to_next_tab_stop)
10298            };
10299            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10300            selection.end = selection.start;
10301            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10302            row_delta += tab_size.len;
10303        }
10304
10305        self.transact(window, cx, |this, window, cx| {
10306            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10307            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10308            this.refresh_edit_prediction(true, false, window, cx);
10309        });
10310    }
10311
10312    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10313        if self.read_only(cx) {
10314            return;
10315        }
10316        if self.mode.is_single_line() {
10317            cx.propagate();
10318            return;
10319        }
10320
10321        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10322        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10323        let mut prev_edited_row = 0;
10324        let mut row_delta = 0;
10325        let mut edits = Vec::new();
10326        let buffer = self.buffer.read(cx);
10327        let snapshot = buffer.snapshot(cx);
10328        for selection in &mut selections {
10329            if selection.start.row != prev_edited_row {
10330                row_delta = 0;
10331            }
10332            prev_edited_row = selection.end.row;
10333
10334            row_delta =
10335                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10336        }
10337
10338        self.transact(window, cx, |this, window, cx| {
10339            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10340            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10341        });
10342    }
10343
10344    fn indent_selection(
10345        buffer: &MultiBuffer,
10346        snapshot: &MultiBufferSnapshot,
10347        selection: &mut Selection<Point>,
10348        edits: &mut Vec<(Range<Point>, String)>,
10349        delta_for_start_row: u32,
10350        cx: &App,
10351    ) -> u32 {
10352        let settings = buffer.language_settings_at(selection.start, cx);
10353        let tab_size = settings.tab_size.get();
10354        let indent_kind = if settings.hard_tabs {
10355            IndentKind::Tab
10356        } else {
10357            IndentKind::Space
10358        };
10359        let mut start_row = selection.start.row;
10360        let mut end_row = selection.end.row + 1;
10361
10362        // If a selection ends at the beginning of a line, don't indent
10363        // that last line.
10364        if selection.end.column == 0 && selection.end.row > selection.start.row {
10365            end_row -= 1;
10366        }
10367
10368        // Avoid re-indenting a row that has already been indented by a
10369        // previous selection, but still update this selection's column
10370        // to reflect that indentation.
10371        if delta_for_start_row > 0 {
10372            start_row += 1;
10373            selection.start.column += delta_for_start_row;
10374            if selection.end.row == selection.start.row {
10375                selection.end.column += delta_for_start_row;
10376            }
10377        }
10378
10379        let mut delta_for_end_row = 0;
10380        let has_multiple_rows = start_row + 1 != end_row;
10381        for row in start_row..end_row {
10382            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10383            let indent_delta = match (current_indent.kind, indent_kind) {
10384                (IndentKind::Space, IndentKind::Space) => {
10385                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10386                    IndentSize::spaces(columns_to_next_tab_stop)
10387                }
10388                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10389                (_, IndentKind::Tab) => IndentSize::tab(),
10390            };
10391
10392            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10393                0
10394            } else {
10395                selection.start.column
10396            };
10397            let row_start = Point::new(row, start);
10398            edits.push((
10399                row_start..row_start,
10400                indent_delta.chars().collect::<String>(),
10401            ));
10402
10403            // Update this selection's endpoints to reflect the indentation.
10404            if row == selection.start.row {
10405                selection.start.column += indent_delta.len;
10406            }
10407            if row == selection.end.row {
10408                selection.end.column += indent_delta.len;
10409                delta_for_end_row = indent_delta.len;
10410            }
10411        }
10412
10413        if selection.start.row == selection.end.row {
10414            delta_for_start_row + delta_for_end_row
10415        } else {
10416            delta_for_end_row
10417        }
10418    }
10419
10420    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10421        if self.read_only(cx) {
10422            return;
10423        }
10424        if self.mode.is_single_line() {
10425            cx.propagate();
10426            return;
10427        }
10428
10429        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10430        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10431        let selections = self.selections.all::<Point>(&display_map);
10432        let mut deletion_ranges = Vec::new();
10433        let mut last_outdent = None;
10434        {
10435            let buffer = self.buffer.read(cx);
10436            let snapshot = buffer.snapshot(cx);
10437            for selection in &selections {
10438                let settings = buffer.language_settings_at(selection.start, cx);
10439                let tab_size = settings.tab_size.get();
10440                let mut rows = selection.spanned_rows(false, &display_map);
10441
10442                // Avoid re-outdenting a row that has already been outdented by a
10443                // previous selection.
10444                if let Some(last_row) = last_outdent
10445                    && last_row == rows.start
10446                {
10447                    rows.start = rows.start.next_row();
10448                }
10449                let has_multiple_rows = rows.len() > 1;
10450                for row in rows.iter_rows() {
10451                    let indent_size = snapshot.indent_size_for_line(row);
10452                    if indent_size.len > 0 {
10453                        let deletion_len = match indent_size.kind {
10454                            IndentKind::Space => {
10455                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10456                                if columns_to_prev_tab_stop == 0 {
10457                                    tab_size
10458                                } else {
10459                                    columns_to_prev_tab_stop
10460                                }
10461                            }
10462                            IndentKind::Tab => 1,
10463                        };
10464                        let start = if has_multiple_rows
10465                            || deletion_len > selection.start.column
10466                            || indent_size.len < selection.start.column
10467                        {
10468                            0
10469                        } else {
10470                            selection.start.column - deletion_len
10471                        };
10472                        deletion_ranges.push(
10473                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10474                        );
10475                        last_outdent = Some(row);
10476                    }
10477                }
10478            }
10479        }
10480
10481        self.transact(window, cx, |this, window, cx| {
10482            this.buffer.update(cx, |buffer, cx| {
10483                let empty_str: Arc<str> = Arc::default();
10484                buffer.edit(
10485                    deletion_ranges
10486                        .into_iter()
10487                        .map(|range| (range, empty_str.clone())),
10488                    None,
10489                    cx,
10490                );
10491            });
10492            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10493            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10494        });
10495    }
10496
10497    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10498        if self.read_only(cx) {
10499            return;
10500        }
10501        if self.mode.is_single_line() {
10502            cx.propagate();
10503            return;
10504        }
10505
10506        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10507        let selections = self
10508            .selections
10509            .all::<usize>(&self.display_snapshot(cx))
10510            .into_iter()
10511            .map(|s| s.range());
10512
10513        self.transact(window, cx, |this, window, cx| {
10514            this.buffer.update(cx, |buffer, cx| {
10515                buffer.autoindent_ranges(selections, cx);
10516            });
10517            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10518            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10519        });
10520    }
10521
10522    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10523        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10524        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10525        let selections = self.selections.all::<Point>(&display_map);
10526
10527        let mut new_cursors = Vec::new();
10528        let mut edit_ranges = Vec::new();
10529        let mut selections = selections.iter().peekable();
10530        while let Some(selection) = selections.next() {
10531            let mut rows = selection.spanned_rows(false, &display_map);
10532
10533            // Accumulate contiguous regions of rows that we want to delete.
10534            while let Some(next_selection) = selections.peek() {
10535                let next_rows = next_selection.spanned_rows(false, &display_map);
10536                if next_rows.start <= rows.end {
10537                    rows.end = next_rows.end;
10538                    selections.next().unwrap();
10539                } else {
10540                    break;
10541                }
10542            }
10543
10544            let buffer = display_map.buffer_snapshot();
10545            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10546            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10547                // If there's a line after the range, delete the \n from the end of the row range
10548                (
10549                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10550                    rows.end,
10551                )
10552            } else {
10553                // If there isn't a line after the range, delete the \n from the line before the
10554                // start of the row range
10555                edit_start = edit_start.saturating_sub(1);
10556                (buffer.len(), rows.start.previous_row())
10557            };
10558
10559            let text_layout_details = self.text_layout_details(window);
10560            let x = display_map.x_for_display_point(
10561                selection.head().to_display_point(&display_map),
10562                &text_layout_details,
10563            );
10564            let row = Point::new(target_row.0, 0)
10565                .to_display_point(&display_map)
10566                .row();
10567            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10568
10569            new_cursors.push((
10570                selection.id,
10571                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10572                SelectionGoal::None,
10573            ));
10574            edit_ranges.push(edit_start..edit_end);
10575        }
10576
10577        self.transact(window, cx, |this, window, cx| {
10578            let buffer = this.buffer.update(cx, |buffer, cx| {
10579                let empty_str: Arc<str> = Arc::default();
10580                buffer.edit(
10581                    edit_ranges
10582                        .into_iter()
10583                        .map(|range| (range, empty_str.clone())),
10584                    None,
10585                    cx,
10586                );
10587                buffer.snapshot(cx)
10588            });
10589            let new_selections = new_cursors
10590                .into_iter()
10591                .map(|(id, cursor, goal)| {
10592                    let cursor = cursor.to_point(&buffer);
10593                    Selection {
10594                        id,
10595                        start: cursor,
10596                        end: cursor,
10597                        reversed: false,
10598                        goal,
10599                    }
10600                })
10601                .collect();
10602
10603            this.change_selections(Default::default(), window, cx, |s| {
10604                s.select(new_selections);
10605            });
10606        });
10607    }
10608
10609    pub fn join_lines_impl(
10610        &mut self,
10611        insert_whitespace: bool,
10612        window: &mut Window,
10613        cx: &mut Context<Self>,
10614    ) {
10615        if self.read_only(cx) {
10616            return;
10617        }
10618        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10619        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10620            let start = MultiBufferRow(selection.start.row);
10621            // Treat single line selections as if they include the next line. Otherwise this action
10622            // would do nothing for single line selections individual cursors.
10623            let end = if selection.start.row == selection.end.row {
10624                MultiBufferRow(selection.start.row + 1)
10625            } else {
10626                MultiBufferRow(selection.end.row)
10627            };
10628
10629            if let Some(last_row_range) = row_ranges.last_mut()
10630                && start <= last_row_range.end
10631            {
10632                last_row_range.end = end;
10633                continue;
10634            }
10635            row_ranges.push(start..end);
10636        }
10637
10638        let snapshot = self.buffer.read(cx).snapshot(cx);
10639        let mut cursor_positions = Vec::new();
10640        for row_range in &row_ranges {
10641            let anchor = snapshot.anchor_before(Point::new(
10642                row_range.end.previous_row().0,
10643                snapshot.line_len(row_range.end.previous_row()),
10644            ));
10645            cursor_positions.push(anchor..anchor);
10646        }
10647
10648        self.transact(window, cx, |this, window, cx| {
10649            for row_range in row_ranges.into_iter().rev() {
10650                for row in row_range.iter_rows().rev() {
10651                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10652                    let next_line_row = row.next_row();
10653                    let indent = snapshot.indent_size_for_line(next_line_row);
10654                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10655
10656                    let replace =
10657                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10658                            " "
10659                        } else {
10660                            ""
10661                        };
10662
10663                    this.buffer.update(cx, |buffer, cx| {
10664                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10665                    });
10666                }
10667            }
10668
10669            this.change_selections(Default::default(), window, cx, |s| {
10670                s.select_anchor_ranges(cursor_positions)
10671            });
10672        });
10673    }
10674
10675    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10676        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10677        self.join_lines_impl(true, window, cx);
10678    }
10679
10680    pub fn sort_lines_case_sensitive(
10681        &mut self,
10682        _: &SortLinesCaseSensitive,
10683        window: &mut Window,
10684        cx: &mut Context<Self>,
10685    ) {
10686        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10687    }
10688
10689    pub fn sort_lines_by_length(
10690        &mut self,
10691        _: &SortLinesByLength,
10692        window: &mut Window,
10693        cx: &mut Context<Self>,
10694    ) {
10695        self.manipulate_immutable_lines(window, cx, |lines| {
10696            lines.sort_by_key(|&line| line.chars().count())
10697        })
10698    }
10699
10700    pub fn sort_lines_case_insensitive(
10701        &mut self,
10702        _: &SortLinesCaseInsensitive,
10703        window: &mut Window,
10704        cx: &mut Context<Self>,
10705    ) {
10706        self.manipulate_immutable_lines(window, cx, |lines| {
10707            lines.sort_by_key(|line| line.to_lowercase())
10708        })
10709    }
10710
10711    pub fn unique_lines_case_insensitive(
10712        &mut self,
10713        _: &UniqueLinesCaseInsensitive,
10714        window: &mut Window,
10715        cx: &mut Context<Self>,
10716    ) {
10717        self.manipulate_immutable_lines(window, cx, |lines| {
10718            let mut seen = HashSet::default();
10719            lines.retain(|line| seen.insert(line.to_lowercase()));
10720        })
10721    }
10722
10723    pub fn unique_lines_case_sensitive(
10724        &mut self,
10725        _: &UniqueLinesCaseSensitive,
10726        window: &mut Window,
10727        cx: &mut Context<Self>,
10728    ) {
10729        self.manipulate_immutable_lines(window, cx, |lines| {
10730            let mut seen = HashSet::default();
10731            lines.retain(|line| seen.insert(*line));
10732        })
10733    }
10734
10735    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10736        let snapshot = self.buffer.read(cx).snapshot(cx);
10737        for selection in self.selections.disjoint_anchors_arc().iter() {
10738            if snapshot
10739                .language_at(selection.start)
10740                .and_then(|lang| lang.config().wrap_characters.as_ref())
10741                .is_some()
10742            {
10743                return true;
10744            }
10745        }
10746        false
10747    }
10748
10749    fn wrap_selections_in_tag(
10750        &mut self,
10751        _: &WrapSelectionsInTag,
10752        window: &mut Window,
10753        cx: &mut Context<Self>,
10754    ) {
10755        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10756
10757        let snapshot = self.buffer.read(cx).snapshot(cx);
10758
10759        let mut edits = Vec::new();
10760        let mut boundaries = Vec::new();
10761
10762        for selection in self
10763            .selections
10764            .all_adjusted(&self.display_snapshot(cx))
10765            .iter()
10766        {
10767            let Some(wrap_config) = snapshot
10768                .language_at(selection.start)
10769                .and_then(|lang| lang.config().wrap_characters.clone())
10770            else {
10771                continue;
10772            };
10773
10774            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10775            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10776
10777            let start_before = snapshot.anchor_before(selection.start);
10778            let end_after = snapshot.anchor_after(selection.end);
10779
10780            edits.push((start_before..start_before, open_tag));
10781            edits.push((end_after..end_after, close_tag));
10782
10783            boundaries.push((
10784                start_before,
10785                end_after,
10786                wrap_config.start_prefix.len(),
10787                wrap_config.end_suffix.len(),
10788            ));
10789        }
10790
10791        if edits.is_empty() {
10792            return;
10793        }
10794
10795        self.transact(window, cx, |this, window, cx| {
10796            let buffer = this.buffer.update(cx, |buffer, cx| {
10797                buffer.edit(edits, None, cx);
10798                buffer.snapshot(cx)
10799            });
10800
10801            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10802            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10803                boundaries.into_iter()
10804            {
10805                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10806                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10807                new_selections.push(open_offset..open_offset);
10808                new_selections.push(close_offset..close_offset);
10809            }
10810
10811            this.change_selections(Default::default(), window, cx, |s| {
10812                s.select_ranges(new_selections);
10813            });
10814
10815            this.request_autoscroll(Autoscroll::fit(), cx);
10816        });
10817    }
10818
10819    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10820        let Some(project) = self.project.clone() else {
10821            return;
10822        };
10823        self.reload(project, window, cx)
10824            .detach_and_notify_err(window, cx);
10825    }
10826
10827    pub fn restore_file(
10828        &mut self,
10829        _: &::git::RestoreFile,
10830        window: &mut Window,
10831        cx: &mut Context<Self>,
10832    ) {
10833        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10834        let mut buffer_ids = HashSet::default();
10835        let snapshot = self.buffer().read(cx).snapshot(cx);
10836        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10837            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10838        }
10839
10840        let buffer = self.buffer().read(cx);
10841        let ranges = buffer_ids
10842            .into_iter()
10843            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10844            .collect::<Vec<_>>();
10845
10846        self.restore_hunks_in_ranges(ranges, window, cx);
10847    }
10848
10849    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10850        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10851        let selections = self
10852            .selections
10853            .all(&self.display_snapshot(cx))
10854            .into_iter()
10855            .map(|s| s.range())
10856            .collect();
10857        self.restore_hunks_in_ranges(selections, window, cx);
10858    }
10859
10860    pub fn restore_hunks_in_ranges(
10861        &mut self,
10862        ranges: Vec<Range<Point>>,
10863        window: &mut Window,
10864        cx: &mut Context<Editor>,
10865    ) {
10866        let mut revert_changes = HashMap::default();
10867        let chunk_by = self
10868            .snapshot(window, cx)
10869            .hunks_for_ranges(ranges)
10870            .into_iter()
10871            .chunk_by(|hunk| hunk.buffer_id);
10872        for (buffer_id, hunks) in &chunk_by {
10873            let hunks = hunks.collect::<Vec<_>>();
10874            for hunk in &hunks {
10875                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10876            }
10877            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10878        }
10879        drop(chunk_by);
10880        if !revert_changes.is_empty() {
10881            self.transact(window, cx, |editor, window, cx| {
10882                editor.restore(revert_changes, window, cx);
10883            });
10884        }
10885    }
10886
10887    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10888        if let Some(status) = self
10889            .addons
10890            .iter()
10891            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10892        {
10893            return Some(status);
10894        }
10895        self.project
10896            .as_ref()?
10897            .read(cx)
10898            .status_for_buffer_id(buffer_id, cx)
10899    }
10900
10901    pub fn open_active_item_in_terminal(
10902        &mut self,
10903        _: &OpenInTerminal,
10904        window: &mut Window,
10905        cx: &mut Context<Self>,
10906    ) {
10907        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10908            let project_path = buffer.read(cx).project_path(cx)?;
10909            let project = self.project()?.read(cx);
10910            let entry = project.entry_for_path(&project_path, cx)?;
10911            let parent = match &entry.canonical_path {
10912                Some(canonical_path) => canonical_path.to_path_buf(),
10913                None => project.absolute_path(&project_path, cx)?,
10914            }
10915            .parent()?
10916            .to_path_buf();
10917            Some(parent)
10918        }) {
10919            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10920        }
10921    }
10922
10923    fn set_breakpoint_context_menu(
10924        &mut self,
10925        display_row: DisplayRow,
10926        position: Option<Anchor>,
10927        clicked_point: gpui::Point<Pixels>,
10928        window: &mut Window,
10929        cx: &mut Context<Self>,
10930    ) {
10931        let source = self
10932            .buffer
10933            .read(cx)
10934            .snapshot(cx)
10935            .anchor_before(Point::new(display_row.0, 0u32));
10936
10937        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10938
10939        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10940            self,
10941            source,
10942            clicked_point,
10943            context_menu,
10944            window,
10945            cx,
10946        );
10947    }
10948
10949    fn add_edit_breakpoint_block(
10950        &mut self,
10951        anchor: Anchor,
10952        breakpoint: &Breakpoint,
10953        edit_action: BreakpointPromptEditAction,
10954        window: &mut Window,
10955        cx: &mut Context<Self>,
10956    ) {
10957        let weak_editor = cx.weak_entity();
10958        let bp_prompt = cx.new(|cx| {
10959            BreakpointPromptEditor::new(
10960                weak_editor,
10961                anchor,
10962                breakpoint.clone(),
10963                edit_action,
10964                window,
10965                cx,
10966            )
10967        });
10968
10969        let height = bp_prompt.update(cx, |this, cx| {
10970            this.prompt
10971                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10972        });
10973        let cloned_prompt = bp_prompt.clone();
10974        let blocks = vec![BlockProperties {
10975            style: BlockStyle::Sticky,
10976            placement: BlockPlacement::Above(anchor),
10977            height: Some(height),
10978            render: Arc::new(move |cx| {
10979                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10980                cloned_prompt.clone().into_any_element()
10981            }),
10982            priority: 0,
10983        }];
10984
10985        let focus_handle = bp_prompt.focus_handle(cx);
10986        window.focus(&focus_handle);
10987
10988        let block_ids = self.insert_blocks(blocks, None, cx);
10989        bp_prompt.update(cx, |prompt, _| {
10990            prompt.add_block_ids(block_ids);
10991        });
10992    }
10993
10994    pub(crate) fn breakpoint_at_row(
10995        &self,
10996        row: u32,
10997        window: &mut Window,
10998        cx: &mut Context<Self>,
10999    ) -> Option<(Anchor, Breakpoint)> {
11000        let snapshot = self.snapshot(window, cx);
11001        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11002
11003        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11004    }
11005
11006    pub(crate) fn breakpoint_at_anchor(
11007        &self,
11008        breakpoint_position: Anchor,
11009        snapshot: &EditorSnapshot,
11010        cx: &mut Context<Self>,
11011    ) -> Option<(Anchor, Breakpoint)> {
11012        let buffer = self
11013            .buffer
11014            .read(cx)
11015            .buffer_for_anchor(breakpoint_position, cx)?;
11016
11017        let enclosing_excerpt = breakpoint_position.excerpt_id;
11018        let buffer_snapshot = buffer.read(cx).snapshot();
11019
11020        let row = buffer_snapshot
11021            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11022            .row;
11023
11024        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11025        let anchor_end = snapshot
11026            .buffer_snapshot()
11027            .anchor_after(Point::new(row, line_len));
11028
11029        self.breakpoint_store
11030            .as_ref()?
11031            .read_with(cx, |breakpoint_store, cx| {
11032                breakpoint_store
11033                    .breakpoints(
11034                        &buffer,
11035                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11036                        &buffer_snapshot,
11037                        cx,
11038                    )
11039                    .next()
11040                    .and_then(|(bp, _)| {
11041                        let breakpoint_row = buffer_snapshot
11042                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11043                            .row;
11044
11045                        if breakpoint_row == row {
11046                            snapshot
11047                                .buffer_snapshot()
11048                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11049                                .map(|position| (position, bp.bp.clone()))
11050                        } else {
11051                            None
11052                        }
11053                    })
11054            })
11055    }
11056
11057    pub fn edit_log_breakpoint(
11058        &mut self,
11059        _: &EditLogBreakpoint,
11060        window: &mut Window,
11061        cx: &mut Context<Self>,
11062    ) {
11063        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11064            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11065                message: None,
11066                state: BreakpointState::Enabled,
11067                condition: None,
11068                hit_condition: None,
11069            });
11070
11071            self.add_edit_breakpoint_block(
11072                anchor,
11073                &breakpoint,
11074                BreakpointPromptEditAction::Log,
11075                window,
11076                cx,
11077            );
11078        }
11079    }
11080
11081    fn breakpoints_at_cursors(
11082        &self,
11083        window: &mut Window,
11084        cx: &mut Context<Self>,
11085    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11086        let snapshot = self.snapshot(window, cx);
11087        let cursors = self
11088            .selections
11089            .disjoint_anchors_arc()
11090            .iter()
11091            .map(|selection| {
11092                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11093
11094                let breakpoint_position = self
11095                    .breakpoint_at_row(cursor_position.row, window, cx)
11096                    .map(|bp| bp.0)
11097                    .unwrap_or_else(|| {
11098                        snapshot
11099                            .display_snapshot
11100                            .buffer_snapshot()
11101                            .anchor_after(Point::new(cursor_position.row, 0))
11102                    });
11103
11104                let breakpoint = self
11105                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11106                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11107
11108                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11109            })
11110            // 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.
11111            .collect::<HashMap<Anchor, _>>();
11112
11113        cursors.into_iter().collect()
11114    }
11115
11116    pub fn enable_breakpoint(
11117        &mut self,
11118        _: &crate::actions::EnableBreakpoint,
11119        window: &mut Window,
11120        cx: &mut Context<Self>,
11121    ) {
11122        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11123            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11124                continue;
11125            };
11126            self.edit_breakpoint_at_anchor(
11127                anchor,
11128                breakpoint,
11129                BreakpointEditAction::InvertState,
11130                cx,
11131            );
11132        }
11133    }
11134
11135    pub fn disable_breakpoint(
11136        &mut self,
11137        _: &crate::actions::DisableBreakpoint,
11138        window: &mut Window,
11139        cx: &mut Context<Self>,
11140    ) {
11141        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11142            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11143                continue;
11144            };
11145            self.edit_breakpoint_at_anchor(
11146                anchor,
11147                breakpoint,
11148                BreakpointEditAction::InvertState,
11149                cx,
11150            );
11151        }
11152    }
11153
11154    pub fn toggle_breakpoint(
11155        &mut self,
11156        _: &crate::actions::ToggleBreakpoint,
11157        window: &mut Window,
11158        cx: &mut Context<Self>,
11159    ) {
11160        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11161            if let Some(breakpoint) = breakpoint {
11162                self.edit_breakpoint_at_anchor(
11163                    anchor,
11164                    breakpoint,
11165                    BreakpointEditAction::Toggle,
11166                    cx,
11167                );
11168            } else {
11169                self.edit_breakpoint_at_anchor(
11170                    anchor,
11171                    Breakpoint::new_standard(),
11172                    BreakpointEditAction::Toggle,
11173                    cx,
11174                );
11175            }
11176        }
11177    }
11178
11179    pub fn edit_breakpoint_at_anchor(
11180        &mut self,
11181        breakpoint_position: Anchor,
11182        breakpoint: Breakpoint,
11183        edit_action: BreakpointEditAction,
11184        cx: &mut Context<Self>,
11185    ) {
11186        let Some(breakpoint_store) = &self.breakpoint_store else {
11187            return;
11188        };
11189
11190        let Some(buffer) = self
11191            .buffer
11192            .read(cx)
11193            .buffer_for_anchor(breakpoint_position, cx)
11194        else {
11195            return;
11196        };
11197
11198        breakpoint_store.update(cx, |breakpoint_store, cx| {
11199            breakpoint_store.toggle_breakpoint(
11200                buffer,
11201                BreakpointWithPosition {
11202                    position: breakpoint_position.text_anchor,
11203                    bp: breakpoint,
11204                },
11205                edit_action,
11206                cx,
11207            );
11208        });
11209
11210        cx.notify();
11211    }
11212
11213    #[cfg(any(test, feature = "test-support"))]
11214    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11215        self.breakpoint_store.clone()
11216    }
11217
11218    pub fn prepare_restore_change(
11219        &self,
11220        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11221        hunk: &MultiBufferDiffHunk,
11222        cx: &mut App,
11223    ) -> Option<()> {
11224        if hunk.is_created_file() {
11225            return None;
11226        }
11227        let buffer = self.buffer.read(cx);
11228        let diff = buffer.diff_for(hunk.buffer_id)?;
11229        let buffer = buffer.buffer(hunk.buffer_id)?;
11230        let buffer = buffer.read(cx);
11231        let original_text = diff
11232            .read(cx)
11233            .base_text()
11234            .as_rope()
11235            .slice(hunk.diff_base_byte_range.clone());
11236        let buffer_snapshot = buffer.snapshot();
11237        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11238        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11239            probe
11240                .0
11241                .start
11242                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11243                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11244        }) {
11245            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11246            Some(())
11247        } else {
11248            None
11249        }
11250    }
11251
11252    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11253        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11254    }
11255
11256    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11257        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11258    }
11259
11260    fn manipulate_lines<M>(
11261        &mut self,
11262        window: &mut Window,
11263        cx: &mut Context<Self>,
11264        mut manipulate: M,
11265    ) where
11266        M: FnMut(&str) -> LineManipulationResult,
11267    {
11268        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11269
11270        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11271        let buffer = self.buffer.read(cx).snapshot(cx);
11272
11273        let mut edits = Vec::new();
11274
11275        let selections = self.selections.all::<Point>(&display_map);
11276        let mut selections = selections.iter().peekable();
11277        let mut contiguous_row_selections = Vec::new();
11278        let mut new_selections = Vec::new();
11279        let mut added_lines = 0;
11280        let mut removed_lines = 0;
11281
11282        while let Some(selection) = selections.next() {
11283            let (start_row, end_row) = consume_contiguous_rows(
11284                &mut contiguous_row_selections,
11285                selection,
11286                &display_map,
11287                &mut selections,
11288            );
11289
11290            let start_point = Point::new(start_row.0, 0);
11291            let end_point = Point::new(
11292                end_row.previous_row().0,
11293                buffer.line_len(end_row.previous_row()),
11294            );
11295            let text = buffer
11296                .text_for_range(start_point..end_point)
11297                .collect::<String>();
11298
11299            let LineManipulationResult {
11300                new_text,
11301                line_count_before,
11302                line_count_after,
11303            } = manipulate(&text);
11304
11305            edits.push((start_point..end_point, new_text));
11306
11307            // Selections must change based on added and removed line count
11308            let start_row =
11309                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11310            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11311            new_selections.push(Selection {
11312                id: selection.id,
11313                start: start_row,
11314                end: end_row,
11315                goal: SelectionGoal::None,
11316                reversed: selection.reversed,
11317            });
11318
11319            if line_count_after > line_count_before {
11320                added_lines += line_count_after - line_count_before;
11321            } else if line_count_before > line_count_after {
11322                removed_lines += line_count_before - line_count_after;
11323            }
11324        }
11325
11326        self.transact(window, cx, |this, window, cx| {
11327            let buffer = this.buffer.update(cx, |buffer, cx| {
11328                buffer.edit(edits, None, cx);
11329                buffer.snapshot(cx)
11330            });
11331
11332            // Recalculate offsets on newly edited buffer
11333            let new_selections = new_selections
11334                .iter()
11335                .map(|s| {
11336                    let start_point = Point::new(s.start.0, 0);
11337                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11338                    Selection {
11339                        id: s.id,
11340                        start: buffer.point_to_offset(start_point),
11341                        end: buffer.point_to_offset(end_point),
11342                        goal: s.goal,
11343                        reversed: s.reversed,
11344                    }
11345                })
11346                .collect();
11347
11348            this.change_selections(Default::default(), window, cx, |s| {
11349                s.select(new_selections);
11350            });
11351
11352            this.request_autoscroll(Autoscroll::fit(), cx);
11353        });
11354    }
11355
11356    fn manipulate_immutable_lines<Fn>(
11357        &mut self,
11358        window: &mut Window,
11359        cx: &mut Context<Self>,
11360        mut callback: Fn,
11361    ) where
11362        Fn: FnMut(&mut Vec<&str>),
11363    {
11364        self.manipulate_lines(window, cx, |text| {
11365            let mut lines: Vec<&str> = text.split('\n').collect();
11366            let line_count_before = lines.len();
11367
11368            callback(&mut lines);
11369
11370            LineManipulationResult {
11371                new_text: lines.join("\n"),
11372                line_count_before,
11373                line_count_after: lines.len(),
11374            }
11375        });
11376    }
11377
11378    fn manipulate_mutable_lines<Fn>(
11379        &mut self,
11380        window: &mut Window,
11381        cx: &mut Context<Self>,
11382        mut callback: Fn,
11383    ) where
11384        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11385    {
11386        self.manipulate_lines(window, cx, |text| {
11387            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11388            let line_count_before = lines.len();
11389
11390            callback(&mut lines);
11391
11392            LineManipulationResult {
11393                new_text: lines.join("\n"),
11394                line_count_before,
11395                line_count_after: lines.len(),
11396            }
11397        });
11398    }
11399
11400    pub fn convert_indentation_to_spaces(
11401        &mut self,
11402        _: &ConvertIndentationToSpaces,
11403        window: &mut Window,
11404        cx: &mut Context<Self>,
11405    ) {
11406        let settings = self.buffer.read(cx).language_settings(cx);
11407        let tab_size = settings.tab_size.get() as usize;
11408
11409        self.manipulate_mutable_lines(window, cx, |lines| {
11410            // Allocates a reasonably sized scratch buffer once for the whole loop
11411            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11412            // Avoids recomputing spaces that could be inserted many times
11413            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11414                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11415                .collect();
11416
11417            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11418                let mut chars = line.as_ref().chars();
11419                let mut col = 0;
11420                let mut changed = false;
11421
11422                for ch in chars.by_ref() {
11423                    match ch {
11424                        ' ' => {
11425                            reindented_line.push(' ');
11426                            col += 1;
11427                        }
11428                        '\t' => {
11429                            // \t are converted to spaces depending on the current column
11430                            let spaces_len = tab_size - (col % tab_size);
11431                            reindented_line.extend(&space_cache[spaces_len - 1]);
11432                            col += spaces_len;
11433                            changed = true;
11434                        }
11435                        _ => {
11436                            // If we dont append before break, the character is consumed
11437                            reindented_line.push(ch);
11438                            break;
11439                        }
11440                    }
11441                }
11442
11443                if !changed {
11444                    reindented_line.clear();
11445                    continue;
11446                }
11447                // Append the rest of the line and replace old reference with new one
11448                reindented_line.extend(chars);
11449                *line = Cow::Owned(reindented_line.clone());
11450                reindented_line.clear();
11451            }
11452        });
11453    }
11454
11455    pub fn convert_indentation_to_tabs(
11456        &mut self,
11457        _: &ConvertIndentationToTabs,
11458        window: &mut Window,
11459        cx: &mut Context<Self>,
11460    ) {
11461        let settings = self.buffer.read(cx).language_settings(cx);
11462        let tab_size = settings.tab_size.get() as usize;
11463
11464        self.manipulate_mutable_lines(window, cx, |lines| {
11465            // Allocates a reasonably sized buffer once for the whole loop
11466            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11467            // Avoids recomputing spaces that could be inserted many times
11468            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11469                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11470                .collect();
11471
11472            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11473                let mut chars = line.chars();
11474                let mut spaces_count = 0;
11475                let mut first_non_indent_char = None;
11476                let mut changed = false;
11477
11478                for ch in chars.by_ref() {
11479                    match ch {
11480                        ' ' => {
11481                            // Keep track of spaces. Append \t when we reach tab_size
11482                            spaces_count += 1;
11483                            changed = true;
11484                            if spaces_count == tab_size {
11485                                reindented_line.push('\t');
11486                                spaces_count = 0;
11487                            }
11488                        }
11489                        '\t' => {
11490                            reindented_line.push('\t');
11491                            spaces_count = 0;
11492                        }
11493                        _ => {
11494                            // Dont append it yet, we might have remaining spaces
11495                            first_non_indent_char = Some(ch);
11496                            break;
11497                        }
11498                    }
11499                }
11500
11501                if !changed {
11502                    reindented_line.clear();
11503                    continue;
11504                }
11505                // Remaining spaces that didn't make a full tab stop
11506                if spaces_count > 0 {
11507                    reindented_line.extend(&space_cache[spaces_count - 1]);
11508                }
11509                // If we consume an extra character that was not indentation, add it back
11510                if let Some(extra_char) = first_non_indent_char {
11511                    reindented_line.push(extra_char);
11512                }
11513                // Append the rest of the line and replace old reference with new one
11514                reindented_line.extend(chars);
11515                *line = Cow::Owned(reindented_line.clone());
11516                reindented_line.clear();
11517            }
11518        });
11519    }
11520
11521    pub fn convert_to_upper_case(
11522        &mut self,
11523        _: &ConvertToUpperCase,
11524        window: &mut Window,
11525        cx: &mut Context<Self>,
11526    ) {
11527        self.manipulate_text(window, cx, |text| text.to_uppercase())
11528    }
11529
11530    pub fn convert_to_lower_case(
11531        &mut self,
11532        _: &ConvertToLowerCase,
11533        window: &mut Window,
11534        cx: &mut Context<Self>,
11535    ) {
11536        self.manipulate_text(window, cx, |text| text.to_lowercase())
11537    }
11538
11539    pub fn convert_to_title_case(
11540        &mut self,
11541        _: &ConvertToTitleCase,
11542        window: &mut Window,
11543        cx: &mut Context<Self>,
11544    ) {
11545        self.manipulate_text(window, cx, |text| {
11546            text.split('\n')
11547                .map(|line| line.to_case(Case::Title))
11548                .join("\n")
11549        })
11550    }
11551
11552    pub fn convert_to_snake_case(
11553        &mut self,
11554        _: &ConvertToSnakeCase,
11555        window: &mut Window,
11556        cx: &mut Context<Self>,
11557    ) {
11558        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11559    }
11560
11561    pub fn convert_to_kebab_case(
11562        &mut self,
11563        _: &ConvertToKebabCase,
11564        window: &mut Window,
11565        cx: &mut Context<Self>,
11566    ) {
11567        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11568    }
11569
11570    pub fn convert_to_upper_camel_case(
11571        &mut self,
11572        _: &ConvertToUpperCamelCase,
11573        window: &mut Window,
11574        cx: &mut Context<Self>,
11575    ) {
11576        self.manipulate_text(window, cx, |text| {
11577            text.split('\n')
11578                .map(|line| line.to_case(Case::UpperCamel))
11579                .join("\n")
11580        })
11581    }
11582
11583    pub fn convert_to_lower_camel_case(
11584        &mut self,
11585        _: &ConvertToLowerCamelCase,
11586        window: &mut Window,
11587        cx: &mut Context<Self>,
11588    ) {
11589        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11590    }
11591
11592    pub fn convert_to_opposite_case(
11593        &mut self,
11594        _: &ConvertToOppositeCase,
11595        window: &mut Window,
11596        cx: &mut Context<Self>,
11597    ) {
11598        self.manipulate_text(window, cx, |text| {
11599            text.chars()
11600                .fold(String::with_capacity(text.len()), |mut t, c| {
11601                    if c.is_uppercase() {
11602                        t.extend(c.to_lowercase());
11603                    } else {
11604                        t.extend(c.to_uppercase());
11605                    }
11606                    t
11607                })
11608        })
11609    }
11610
11611    pub fn convert_to_sentence_case(
11612        &mut self,
11613        _: &ConvertToSentenceCase,
11614        window: &mut Window,
11615        cx: &mut Context<Self>,
11616    ) {
11617        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11618    }
11619
11620    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11621        self.manipulate_text(window, cx, |text| {
11622            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11623            if has_upper_case_characters {
11624                text.to_lowercase()
11625            } else {
11626                text.to_uppercase()
11627            }
11628        })
11629    }
11630
11631    pub fn convert_to_rot13(
11632        &mut self,
11633        _: &ConvertToRot13,
11634        window: &mut Window,
11635        cx: &mut Context<Self>,
11636    ) {
11637        self.manipulate_text(window, cx, |text| {
11638            text.chars()
11639                .map(|c| match c {
11640                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11641                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11642                    _ => c,
11643                })
11644                .collect()
11645        })
11646    }
11647
11648    pub fn convert_to_rot47(
11649        &mut self,
11650        _: &ConvertToRot47,
11651        window: &mut Window,
11652        cx: &mut Context<Self>,
11653    ) {
11654        self.manipulate_text(window, cx, |text| {
11655            text.chars()
11656                .map(|c| {
11657                    let code_point = c as u32;
11658                    if code_point >= 33 && code_point <= 126 {
11659                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11660                    }
11661                    c
11662                })
11663                .collect()
11664        })
11665    }
11666
11667    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11668    where
11669        Fn: FnMut(&str) -> String,
11670    {
11671        let buffer = self.buffer.read(cx).snapshot(cx);
11672
11673        let mut new_selections = Vec::new();
11674        let mut edits = Vec::new();
11675        let mut selection_adjustment = 0i32;
11676
11677        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11678            let selection_is_empty = selection.is_empty();
11679
11680            let (start, end) = if selection_is_empty {
11681                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11682                (word_range.start, word_range.end)
11683            } else {
11684                (
11685                    buffer.point_to_offset(selection.start),
11686                    buffer.point_to_offset(selection.end),
11687                )
11688            };
11689
11690            let text = buffer.text_for_range(start..end).collect::<String>();
11691            let old_length = text.len() as i32;
11692            let text = callback(&text);
11693
11694            new_selections.push(Selection {
11695                start: (start as i32 - selection_adjustment) as usize,
11696                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11697                goal: SelectionGoal::None,
11698                id: selection.id,
11699                reversed: selection.reversed,
11700            });
11701
11702            selection_adjustment += old_length - text.len() as i32;
11703
11704            edits.push((start..end, text));
11705        }
11706
11707        self.transact(window, cx, |this, window, cx| {
11708            this.buffer.update(cx, |buffer, cx| {
11709                buffer.edit(edits, None, cx);
11710            });
11711
11712            this.change_selections(Default::default(), window, cx, |s| {
11713                s.select(new_selections);
11714            });
11715
11716            this.request_autoscroll(Autoscroll::fit(), cx);
11717        });
11718    }
11719
11720    pub fn move_selection_on_drop(
11721        &mut self,
11722        selection: &Selection<Anchor>,
11723        target: DisplayPoint,
11724        is_cut: bool,
11725        window: &mut Window,
11726        cx: &mut Context<Self>,
11727    ) {
11728        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11729        let buffer = display_map.buffer_snapshot();
11730        let mut edits = Vec::new();
11731        let insert_point = display_map
11732            .clip_point(target, Bias::Left)
11733            .to_point(&display_map);
11734        let text = buffer
11735            .text_for_range(selection.start..selection.end)
11736            .collect::<String>();
11737        if is_cut {
11738            edits.push(((selection.start..selection.end), String::new()));
11739        }
11740        let insert_anchor = buffer.anchor_before(insert_point);
11741        edits.push(((insert_anchor..insert_anchor), text));
11742        let last_edit_start = insert_anchor.bias_left(buffer);
11743        let last_edit_end = insert_anchor.bias_right(buffer);
11744        self.transact(window, cx, |this, window, cx| {
11745            this.buffer.update(cx, |buffer, cx| {
11746                buffer.edit(edits, None, cx);
11747            });
11748            this.change_selections(Default::default(), window, cx, |s| {
11749                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11750            });
11751        });
11752    }
11753
11754    pub fn clear_selection_drag_state(&mut self) {
11755        self.selection_drag_state = SelectionDragState::None;
11756    }
11757
11758    pub fn duplicate(
11759        &mut self,
11760        upwards: bool,
11761        whole_lines: bool,
11762        window: &mut Window,
11763        cx: &mut Context<Self>,
11764    ) {
11765        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11766
11767        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11768        let buffer = display_map.buffer_snapshot();
11769        let selections = self.selections.all::<Point>(&display_map);
11770
11771        let mut edits = Vec::new();
11772        let mut selections_iter = selections.iter().peekable();
11773        while let Some(selection) = selections_iter.next() {
11774            let mut rows = selection.spanned_rows(false, &display_map);
11775            // duplicate line-wise
11776            if whole_lines || selection.start == selection.end {
11777                // Avoid duplicating the same lines twice.
11778                while let Some(next_selection) = selections_iter.peek() {
11779                    let next_rows = next_selection.spanned_rows(false, &display_map);
11780                    if next_rows.start < rows.end {
11781                        rows.end = next_rows.end;
11782                        selections_iter.next().unwrap();
11783                    } else {
11784                        break;
11785                    }
11786                }
11787
11788                // Copy the text from the selected row region and splice it either at the start
11789                // or end of the region.
11790                let start = Point::new(rows.start.0, 0);
11791                let end = Point::new(
11792                    rows.end.previous_row().0,
11793                    buffer.line_len(rows.end.previous_row()),
11794                );
11795
11796                let mut text = buffer.text_for_range(start..end).collect::<String>();
11797
11798                let insert_location = if upwards {
11799                    // When duplicating upward, we need to insert before the current line.
11800                    // If we're on the last line and it doesn't end with a newline,
11801                    // we need to add a newline before the duplicated content.
11802                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11803                        && buffer.max_point().column > 0
11804                        && !text.ends_with('\n');
11805
11806                    if needs_leading_newline {
11807                        text.insert(0, '\n');
11808                        end
11809                    } else {
11810                        text.push('\n');
11811                        Point::new(rows.start.0, 0)
11812                    }
11813                } else {
11814                    text.push('\n');
11815                    start
11816                };
11817                edits.push((insert_location..insert_location, text));
11818            } else {
11819                // duplicate character-wise
11820                let start = selection.start;
11821                let end = selection.end;
11822                let text = buffer.text_for_range(start..end).collect::<String>();
11823                edits.push((selection.end..selection.end, text));
11824            }
11825        }
11826
11827        self.transact(window, cx, |this, window, cx| {
11828            this.buffer.update(cx, |buffer, cx| {
11829                buffer.edit(edits, None, cx);
11830            });
11831
11832            // When duplicating upward with whole lines, move the cursor to the duplicated line
11833            if upwards && whole_lines {
11834                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11835
11836                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11837                    let mut new_ranges = Vec::new();
11838                    let selections = s.all::<Point>(&display_map);
11839                    let mut selections_iter = selections.iter().peekable();
11840
11841                    while let Some(first_selection) = selections_iter.next() {
11842                        // Group contiguous selections together to find the total row span
11843                        let mut group_selections = vec![first_selection];
11844                        let mut rows = first_selection.spanned_rows(false, &display_map);
11845
11846                        while let Some(next_selection) = selections_iter.peek() {
11847                            let next_rows = next_selection.spanned_rows(false, &display_map);
11848                            if next_rows.start < rows.end {
11849                                rows.end = next_rows.end;
11850                                group_selections.push(selections_iter.next().unwrap());
11851                            } else {
11852                                break;
11853                            }
11854                        }
11855
11856                        let row_count = rows.end.0 - rows.start.0;
11857
11858                        // Move all selections in this group up by the total number of duplicated rows
11859                        for selection in group_selections {
11860                            let new_start = Point::new(
11861                                selection.start.row.saturating_sub(row_count),
11862                                selection.start.column,
11863                            );
11864
11865                            let new_end = Point::new(
11866                                selection.end.row.saturating_sub(row_count),
11867                                selection.end.column,
11868                            );
11869
11870                            new_ranges.push(new_start..new_end);
11871                        }
11872                    }
11873
11874                    s.select_ranges(new_ranges);
11875                });
11876            }
11877
11878            this.request_autoscroll(Autoscroll::fit(), cx);
11879        });
11880    }
11881
11882    pub fn duplicate_line_up(
11883        &mut self,
11884        _: &DuplicateLineUp,
11885        window: &mut Window,
11886        cx: &mut Context<Self>,
11887    ) {
11888        self.duplicate(true, true, window, cx);
11889    }
11890
11891    pub fn duplicate_line_down(
11892        &mut self,
11893        _: &DuplicateLineDown,
11894        window: &mut Window,
11895        cx: &mut Context<Self>,
11896    ) {
11897        self.duplicate(false, true, window, cx);
11898    }
11899
11900    pub fn duplicate_selection(
11901        &mut self,
11902        _: &DuplicateSelection,
11903        window: &mut Window,
11904        cx: &mut Context<Self>,
11905    ) {
11906        self.duplicate(false, false, window, cx);
11907    }
11908
11909    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11910        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11911        if self.mode.is_single_line() {
11912            cx.propagate();
11913            return;
11914        }
11915
11916        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11917        let buffer = self.buffer.read(cx).snapshot(cx);
11918
11919        let mut edits = Vec::new();
11920        let mut unfold_ranges = Vec::new();
11921        let mut refold_creases = Vec::new();
11922
11923        let selections = self.selections.all::<Point>(&display_map);
11924        let mut selections = selections.iter().peekable();
11925        let mut contiguous_row_selections = Vec::new();
11926        let mut new_selections = Vec::new();
11927
11928        while let Some(selection) = selections.next() {
11929            // Find all the selections that span a contiguous row range
11930            let (start_row, end_row) = consume_contiguous_rows(
11931                &mut contiguous_row_selections,
11932                selection,
11933                &display_map,
11934                &mut selections,
11935            );
11936
11937            // Move the text spanned by the row range to be before the line preceding the row range
11938            if start_row.0 > 0 {
11939                let range_to_move = Point::new(
11940                    start_row.previous_row().0,
11941                    buffer.line_len(start_row.previous_row()),
11942                )
11943                    ..Point::new(
11944                        end_row.previous_row().0,
11945                        buffer.line_len(end_row.previous_row()),
11946                    );
11947                let insertion_point = display_map
11948                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11949                    .0;
11950
11951                // Don't move lines across excerpts
11952                if buffer
11953                    .excerpt_containing(insertion_point..range_to_move.end)
11954                    .is_some()
11955                {
11956                    let text = buffer
11957                        .text_for_range(range_to_move.clone())
11958                        .flat_map(|s| s.chars())
11959                        .skip(1)
11960                        .chain(['\n'])
11961                        .collect::<String>();
11962
11963                    edits.push((
11964                        buffer.anchor_after(range_to_move.start)
11965                            ..buffer.anchor_before(range_to_move.end),
11966                        String::new(),
11967                    ));
11968                    let insertion_anchor = buffer.anchor_after(insertion_point);
11969                    edits.push((insertion_anchor..insertion_anchor, text));
11970
11971                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11972
11973                    // Move selections up
11974                    new_selections.extend(contiguous_row_selections.drain(..).map(
11975                        |mut selection| {
11976                            selection.start.row -= row_delta;
11977                            selection.end.row -= row_delta;
11978                            selection
11979                        },
11980                    ));
11981
11982                    // Move folds up
11983                    unfold_ranges.push(range_to_move.clone());
11984                    for fold in display_map.folds_in_range(
11985                        buffer.anchor_before(range_to_move.start)
11986                            ..buffer.anchor_after(range_to_move.end),
11987                    ) {
11988                        let mut start = fold.range.start.to_point(&buffer);
11989                        let mut end = fold.range.end.to_point(&buffer);
11990                        start.row -= row_delta;
11991                        end.row -= row_delta;
11992                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11993                    }
11994                }
11995            }
11996
11997            // If we didn't move line(s), preserve the existing selections
11998            new_selections.append(&mut contiguous_row_selections);
11999        }
12000
12001        self.transact(window, cx, |this, window, cx| {
12002            this.unfold_ranges(&unfold_ranges, true, true, cx);
12003            this.buffer.update(cx, |buffer, cx| {
12004                for (range, text) in edits {
12005                    buffer.edit([(range, text)], None, cx);
12006                }
12007            });
12008            this.fold_creases(refold_creases, true, window, cx);
12009            this.change_selections(Default::default(), window, cx, |s| {
12010                s.select(new_selections);
12011            })
12012        });
12013    }
12014
12015    pub fn move_line_down(
12016        &mut self,
12017        _: &MoveLineDown,
12018        window: &mut Window,
12019        cx: &mut Context<Self>,
12020    ) {
12021        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12022        if self.mode.is_single_line() {
12023            cx.propagate();
12024            return;
12025        }
12026
12027        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12028        let buffer = self.buffer.read(cx).snapshot(cx);
12029
12030        let mut edits = Vec::new();
12031        let mut unfold_ranges = Vec::new();
12032        let mut refold_creases = Vec::new();
12033
12034        let selections = self.selections.all::<Point>(&display_map);
12035        let mut selections = selections.iter().peekable();
12036        let mut contiguous_row_selections = Vec::new();
12037        let mut new_selections = Vec::new();
12038
12039        while let Some(selection) = selections.next() {
12040            // Find all the selections that span a contiguous row range
12041            let (start_row, end_row) = consume_contiguous_rows(
12042                &mut contiguous_row_selections,
12043                selection,
12044                &display_map,
12045                &mut selections,
12046            );
12047
12048            // Move the text spanned by the row range to be after the last line of the row range
12049            if end_row.0 <= buffer.max_point().row {
12050                let range_to_move =
12051                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12052                let insertion_point = display_map
12053                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12054                    .0;
12055
12056                // Don't move lines across excerpt boundaries
12057                if buffer
12058                    .excerpt_containing(range_to_move.start..insertion_point)
12059                    .is_some()
12060                {
12061                    let mut text = String::from("\n");
12062                    text.extend(buffer.text_for_range(range_to_move.clone()));
12063                    text.pop(); // Drop trailing newline
12064                    edits.push((
12065                        buffer.anchor_after(range_to_move.start)
12066                            ..buffer.anchor_before(range_to_move.end),
12067                        String::new(),
12068                    ));
12069                    let insertion_anchor = buffer.anchor_after(insertion_point);
12070                    edits.push((insertion_anchor..insertion_anchor, text));
12071
12072                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12073
12074                    // Move selections down
12075                    new_selections.extend(contiguous_row_selections.drain(..).map(
12076                        |mut selection| {
12077                            selection.start.row += row_delta;
12078                            selection.end.row += row_delta;
12079                            selection
12080                        },
12081                    ));
12082
12083                    // Move folds down
12084                    unfold_ranges.push(range_to_move.clone());
12085                    for fold in display_map.folds_in_range(
12086                        buffer.anchor_before(range_to_move.start)
12087                            ..buffer.anchor_after(range_to_move.end),
12088                    ) {
12089                        let mut start = fold.range.start.to_point(&buffer);
12090                        let mut end = fold.range.end.to_point(&buffer);
12091                        start.row += row_delta;
12092                        end.row += row_delta;
12093                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12094                    }
12095                }
12096            }
12097
12098            // If we didn't move line(s), preserve the existing selections
12099            new_selections.append(&mut contiguous_row_selections);
12100        }
12101
12102        self.transact(window, cx, |this, window, cx| {
12103            this.unfold_ranges(&unfold_ranges, true, true, cx);
12104            this.buffer.update(cx, |buffer, cx| {
12105                for (range, text) in edits {
12106                    buffer.edit([(range, text)], None, cx);
12107                }
12108            });
12109            this.fold_creases(refold_creases, true, window, cx);
12110            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12111        });
12112    }
12113
12114    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12115        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12116        let text_layout_details = &self.text_layout_details(window);
12117        self.transact(window, cx, |this, window, cx| {
12118            let edits = this.change_selections(Default::default(), window, cx, |s| {
12119                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12120                s.move_with(|display_map, selection| {
12121                    if !selection.is_empty() {
12122                        return;
12123                    }
12124
12125                    let mut head = selection.head();
12126                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12127                    if head.column() == display_map.line_len(head.row()) {
12128                        transpose_offset = display_map
12129                            .buffer_snapshot()
12130                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12131                    }
12132
12133                    if transpose_offset == 0 {
12134                        return;
12135                    }
12136
12137                    *head.column_mut() += 1;
12138                    head = display_map.clip_point(head, Bias::Right);
12139                    let goal = SelectionGoal::HorizontalPosition(
12140                        display_map
12141                            .x_for_display_point(head, text_layout_details)
12142                            .into(),
12143                    );
12144                    selection.collapse_to(head, goal);
12145
12146                    let transpose_start = display_map
12147                        .buffer_snapshot()
12148                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12149                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12150                        let transpose_end = display_map
12151                            .buffer_snapshot()
12152                            .clip_offset(transpose_offset + 1, Bias::Right);
12153                        if let Some(ch) = display_map
12154                            .buffer_snapshot()
12155                            .chars_at(transpose_start)
12156                            .next()
12157                        {
12158                            edits.push((transpose_start..transpose_offset, String::new()));
12159                            edits.push((transpose_end..transpose_end, ch.to_string()));
12160                        }
12161                    }
12162                });
12163                edits
12164            });
12165            this.buffer
12166                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12167            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12168            this.change_selections(Default::default(), window, cx, |s| {
12169                s.select(selections);
12170            });
12171        });
12172    }
12173
12174    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12175        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12176        if self.mode.is_single_line() {
12177            cx.propagate();
12178            return;
12179        }
12180
12181        self.rewrap_impl(RewrapOptions::default(), cx)
12182    }
12183
12184    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12185        let buffer = self.buffer.read(cx).snapshot(cx);
12186        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12187
12188        #[derive(Clone, Debug, PartialEq)]
12189        enum CommentFormat {
12190            /// single line comment, with prefix for line
12191            Line(String),
12192            /// single line within a block comment, with prefix for line
12193            BlockLine(String),
12194            /// a single line of a block comment that includes the initial delimiter
12195            BlockCommentWithStart(BlockCommentConfig),
12196            /// a single line of a block comment that includes the ending delimiter
12197            BlockCommentWithEnd(BlockCommentConfig),
12198        }
12199
12200        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12201        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12202            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12203                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12204                .peekable();
12205
12206            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12207                row
12208            } else {
12209                return Vec::new();
12210            };
12211
12212            let language_settings = buffer.language_settings_at(selection.head(), cx);
12213            let language_scope = buffer.language_scope_at(selection.head());
12214
12215            let indent_and_prefix_for_row =
12216                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12217                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12218                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12219                        &language_scope
12220                    {
12221                        let indent_end = Point::new(row, indent.len);
12222                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12223                        let line_text_after_indent = buffer
12224                            .text_for_range(indent_end..line_end)
12225                            .collect::<String>();
12226
12227                        let is_within_comment_override = buffer
12228                            .language_scope_at(indent_end)
12229                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12230                        let comment_delimiters = if is_within_comment_override {
12231                            // we are within a comment syntax node, but we don't
12232                            // yet know what kind of comment: block, doc or line
12233                            match (
12234                                language_scope.documentation_comment(),
12235                                language_scope.block_comment(),
12236                            ) {
12237                                (Some(config), _) | (_, Some(config))
12238                                    if buffer.contains_str_at(indent_end, &config.start) =>
12239                                {
12240                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12241                                }
12242                                (Some(config), _) | (_, Some(config))
12243                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12244                                {
12245                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12246                                }
12247                                (Some(config), _) | (_, Some(config))
12248                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12249                                {
12250                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12251                                }
12252                                (_, _) => language_scope
12253                                    .line_comment_prefixes()
12254                                    .iter()
12255                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12256                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12257                            }
12258                        } else {
12259                            // we not in an overridden comment node, but we may
12260                            // be within a non-overridden line comment node
12261                            language_scope
12262                                .line_comment_prefixes()
12263                                .iter()
12264                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12265                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12266                        };
12267
12268                        let rewrap_prefix = language_scope
12269                            .rewrap_prefixes()
12270                            .iter()
12271                            .find_map(|prefix_regex| {
12272                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12273                                    if mat.start() == 0 {
12274                                        Some(mat.as_str().to_string())
12275                                    } else {
12276                                        None
12277                                    }
12278                                })
12279                            })
12280                            .flatten();
12281                        (comment_delimiters, rewrap_prefix)
12282                    } else {
12283                        (None, None)
12284                    };
12285                    (indent, comment_prefix, rewrap_prefix)
12286                };
12287
12288            let mut ranges = Vec::new();
12289            let from_empty_selection = selection.is_empty();
12290
12291            let mut current_range_start = first_row;
12292            let mut prev_row = first_row;
12293            let (
12294                mut current_range_indent,
12295                mut current_range_comment_delimiters,
12296                mut current_range_rewrap_prefix,
12297            ) = indent_and_prefix_for_row(first_row);
12298
12299            for row in non_blank_rows_iter.skip(1) {
12300                let has_paragraph_break = row > prev_row + 1;
12301
12302                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12303                    indent_and_prefix_for_row(row);
12304
12305                let has_indent_change = row_indent != current_range_indent;
12306                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12307
12308                let has_boundary_change = has_comment_change
12309                    || row_rewrap_prefix.is_some()
12310                    || (has_indent_change && current_range_comment_delimiters.is_some());
12311
12312                if has_paragraph_break || has_boundary_change {
12313                    ranges.push((
12314                        language_settings.clone(),
12315                        Point::new(current_range_start, 0)
12316                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12317                        current_range_indent,
12318                        current_range_comment_delimiters.clone(),
12319                        current_range_rewrap_prefix.clone(),
12320                        from_empty_selection,
12321                    ));
12322                    current_range_start = row;
12323                    current_range_indent = row_indent;
12324                    current_range_comment_delimiters = row_comment_delimiters;
12325                    current_range_rewrap_prefix = row_rewrap_prefix;
12326                }
12327                prev_row = row;
12328            }
12329
12330            ranges.push((
12331                language_settings.clone(),
12332                Point::new(current_range_start, 0)
12333                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12334                current_range_indent,
12335                current_range_comment_delimiters,
12336                current_range_rewrap_prefix,
12337                from_empty_selection,
12338            ));
12339
12340            ranges
12341        });
12342
12343        let mut edits = Vec::new();
12344        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12345
12346        for (
12347            language_settings,
12348            wrap_range,
12349            mut indent_size,
12350            comment_prefix,
12351            rewrap_prefix,
12352            from_empty_selection,
12353        ) in wrap_ranges
12354        {
12355            let mut start_row = wrap_range.start.row;
12356            let mut end_row = wrap_range.end.row;
12357
12358            // Skip selections that overlap with a range that has already been rewrapped.
12359            let selection_range = start_row..end_row;
12360            if rewrapped_row_ranges
12361                .iter()
12362                .any(|range| range.overlaps(&selection_range))
12363            {
12364                continue;
12365            }
12366
12367            let tab_size = language_settings.tab_size;
12368
12369            let (line_prefix, inside_comment) = match &comment_prefix {
12370                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12371                    (Some(prefix.as_str()), true)
12372                }
12373                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12374                    (Some(prefix.as_ref()), true)
12375                }
12376                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12377                    start: _,
12378                    end: _,
12379                    prefix,
12380                    tab_size,
12381                })) => {
12382                    indent_size.len += tab_size;
12383                    (Some(prefix.as_ref()), true)
12384                }
12385                None => (None, false),
12386            };
12387            let indent_prefix = indent_size.chars().collect::<String>();
12388            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12389
12390            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12391                RewrapBehavior::InComments => inside_comment,
12392                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12393                RewrapBehavior::Anywhere => true,
12394            };
12395
12396            let should_rewrap = options.override_language_settings
12397                || allow_rewrap_based_on_language
12398                || self.hard_wrap.is_some();
12399            if !should_rewrap {
12400                continue;
12401            }
12402
12403            if from_empty_selection {
12404                'expand_upwards: while start_row > 0 {
12405                    let prev_row = start_row - 1;
12406                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12407                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12408                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12409                    {
12410                        start_row = prev_row;
12411                    } else {
12412                        break 'expand_upwards;
12413                    }
12414                }
12415
12416                'expand_downwards: while end_row < buffer.max_point().row {
12417                    let next_row = end_row + 1;
12418                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12419                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12420                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12421                    {
12422                        end_row = next_row;
12423                    } else {
12424                        break 'expand_downwards;
12425                    }
12426                }
12427            }
12428
12429            let start = Point::new(start_row, 0);
12430            let start_offset = ToOffset::to_offset(&start, &buffer);
12431            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12432            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12433            let mut first_line_delimiter = None;
12434            let mut last_line_delimiter = None;
12435            let Some(lines_without_prefixes) = selection_text
12436                .lines()
12437                .enumerate()
12438                .map(|(ix, line)| {
12439                    let line_trimmed = line.trim_start();
12440                    if rewrap_prefix.is_some() && ix > 0 {
12441                        Ok(line_trimmed)
12442                    } else if let Some(
12443                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12444                            start,
12445                            prefix,
12446                            end,
12447                            tab_size,
12448                        })
12449                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12450                            start,
12451                            prefix,
12452                            end,
12453                            tab_size,
12454                        }),
12455                    ) = &comment_prefix
12456                    {
12457                        let line_trimmed = line_trimmed
12458                            .strip_prefix(start.as_ref())
12459                            .map(|s| {
12460                                let mut indent_size = indent_size;
12461                                indent_size.len -= tab_size;
12462                                let indent_prefix: String = indent_size.chars().collect();
12463                                first_line_delimiter = Some((indent_prefix, start));
12464                                s.trim_start()
12465                            })
12466                            .unwrap_or(line_trimmed);
12467                        let line_trimmed = line_trimmed
12468                            .strip_suffix(end.as_ref())
12469                            .map(|s| {
12470                                last_line_delimiter = Some(end);
12471                                s.trim_end()
12472                            })
12473                            .unwrap_or(line_trimmed);
12474                        let line_trimmed = line_trimmed
12475                            .strip_prefix(prefix.as_ref())
12476                            .unwrap_or(line_trimmed);
12477                        Ok(line_trimmed)
12478                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12479                        line_trimmed.strip_prefix(prefix).with_context(|| {
12480                            format!("line did not start with prefix {prefix:?}: {line:?}")
12481                        })
12482                    } else {
12483                        line_trimmed
12484                            .strip_prefix(&line_prefix.trim_start())
12485                            .with_context(|| {
12486                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12487                            })
12488                    }
12489                })
12490                .collect::<Result<Vec<_>, _>>()
12491                .log_err()
12492            else {
12493                continue;
12494            };
12495
12496            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12497                buffer
12498                    .language_settings_at(Point::new(start_row, 0), cx)
12499                    .preferred_line_length as usize
12500            });
12501
12502            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12503                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12504            } else {
12505                line_prefix.clone()
12506            };
12507
12508            let wrapped_text = {
12509                let mut wrapped_text = wrap_with_prefix(
12510                    line_prefix,
12511                    subsequent_lines_prefix,
12512                    lines_without_prefixes.join("\n"),
12513                    wrap_column,
12514                    tab_size,
12515                    options.preserve_existing_whitespace,
12516                );
12517
12518                if let Some((indent, delimiter)) = first_line_delimiter {
12519                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12520                }
12521                if let Some(last_line) = last_line_delimiter {
12522                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12523                }
12524
12525                wrapped_text
12526            };
12527
12528            // TODO: should always use char-based diff while still supporting cursor behavior that
12529            // matches vim.
12530            let mut diff_options = DiffOptions::default();
12531            if options.override_language_settings {
12532                diff_options.max_word_diff_len = 0;
12533                diff_options.max_word_diff_line_count = 0;
12534            } else {
12535                diff_options.max_word_diff_len = usize::MAX;
12536                diff_options.max_word_diff_line_count = usize::MAX;
12537            }
12538
12539            for (old_range, new_text) in
12540                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12541            {
12542                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12543                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12544                edits.push((edit_start..edit_end, new_text));
12545            }
12546
12547            rewrapped_row_ranges.push(start_row..=end_row);
12548        }
12549
12550        self.buffer
12551            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12552    }
12553
12554    pub fn cut_common(
12555        &mut self,
12556        cut_no_selection_line: bool,
12557        window: &mut Window,
12558        cx: &mut Context<Self>,
12559    ) -> ClipboardItem {
12560        let mut text = String::new();
12561        let buffer = self.buffer.read(cx).snapshot(cx);
12562        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12563        let mut clipboard_selections = Vec::with_capacity(selections.len());
12564        {
12565            let max_point = buffer.max_point();
12566            let mut is_first = true;
12567            for selection in &mut selections {
12568                let is_entire_line =
12569                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12570                if is_entire_line {
12571                    selection.start = Point::new(selection.start.row, 0);
12572                    if !selection.is_empty() && selection.end.column == 0 {
12573                        selection.end = cmp::min(max_point, selection.end);
12574                    } else {
12575                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12576                    }
12577                    selection.goal = SelectionGoal::None;
12578                }
12579                if is_first {
12580                    is_first = false;
12581                } else {
12582                    text += "\n";
12583                }
12584                let mut len = 0;
12585                for chunk in buffer.text_for_range(selection.start..selection.end) {
12586                    text.push_str(chunk);
12587                    len += chunk.len();
12588                }
12589                clipboard_selections.push(ClipboardSelection {
12590                    len,
12591                    is_entire_line,
12592                    first_line_indent: buffer
12593                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12594                        .len,
12595                });
12596            }
12597        }
12598
12599        self.transact(window, cx, |this, window, cx| {
12600            this.change_selections(Default::default(), window, cx, |s| {
12601                s.select(selections);
12602            });
12603            this.insert("", window, cx);
12604        });
12605        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12606    }
12607
12608    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12609        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12610        let item = self.cut_common(true, window, cx);
12611        cx.write_to_clipboard(item);
12612    }
12613
12614    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12616        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12617            s.move_with(|snapshot, sel| {
12618                if sel.is_empty() {
12619                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12620                }
12621                if sel.is_empty() {
12622                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12623                }
12624            });
12625        });
12626        let item = self.cut_common(false, window, cx);
12627        cx.set_global(KillRing(item))
12628    }
12629
12630    pub fn kill_ring_yank(
12631        &mut self,
12632        _: &KillRingYank,
12633        window: &mut Window,
12634        cx: &mut Context<Self>,
12635    ) {
12636        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12637        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12638            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12639                (kill_ring.text().to_string(), kill_ring.metadata_json())
12640            } else {
12641                return;
12642            }
12643        } else {
12644            return;
12645        };
12646        self.do_paste(&text, metadata, false, window, cx);
12647    }
12648
12649    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12650        self.do_copy(true, cx);
12651    }
12652
12653    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12654        self.do_copy(false, cx);
12655    }
12656
12657    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12658        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12659        let buffer = self.buffer.read(cx).read(cx);
12660        let mut text = String::new();
12661
12662        let mut clipboard_selections = Vec::with_capacity(selections.len());
12663        {
12664            let max_point = buffer.max_point();
12665            let mut is_first = true;
12666            for selection in &selections {
12667                let mut start = selection.start;
12668                let mut end = selection.end;
12669                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12670                let mut add_trailing_newline = false;
12671                if is_entire_line {
12672                    start = Point::new(start.row, 0);
12673                    let next_line_start = Point::new(end.row + 1, 0);
12674                    if next_line_start <= max_point {
12675                        end = next_line_start;
12676                    } else {
12677                        // We're on the last line without a trailing newline.
12678                        // Copy to the end of the line and add a newline afterwards.
12679                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12680                        add_trailing_newline = true;
12681                    }
12682                }
12683
12684                let mut trimmed_selections = Vec::new();
12685                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12686                    let row = MultiBufferRow(start.row);
12687                    let first_indent = buffer.indent_size_for_line(row);
12688                    if first_indent.len == 0 || start.column > first_indent.len {
12689                        trimmed_selections.push(start..end);
12690                    } else {
12691                        trimmed_selections.push(
12692                            Point::new(row.0, first_indent.len)
12693                                ..Point::new(row.0, buffer.line_len(row)),
12694                        );
12695                        for row in start.row + 1..=end.row {
12696                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12697                            if row == end.row {
12698                                line_len = end.column;
12699                            }
12700                            if line_len == 0 {
12701                                trimmed_selections
12702                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12703                                continue;
12704                            }
12705                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12706                            if row_indent_size.len >= first_indent.len {
12707                                trimmed_selections.push(
12708                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12709                                );
12710                            } else {
12711                                trimmed_selections.clear();
12712                                trimmed_selections.push(start..end);
12713                                break;
12714                            }
12715                        }
12716                    }
12717                } else {
12718                    trimmed_selections.push(start..end);
12719                }
12720
12721                for trimmed_range in trimmed_selections {
12722                    if is_first {
12723                        is_first = false;
12724                    } else {
12725                        text += "\n";
12726                    }
12727                    let mut len = 0;
12728                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12729                        text.push_str(chunk);
12730                        len += chunk.len();
12731                    }
12732                    if add_trailing_newline {
12733                        text.push('\n');
12734                        len += 1;
12735                    }
12736                    clipboard_selections.push(ClipboardSelection {
12737                        len,
12738                        is_entire_line,
12739                        first_line_indent: buffer
12740                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12741                            .len,
12742                    });
12743                }
12744            }
12745        }
12746
12747        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12748            text,
12749            clipboard_selections,
12750        ));
12751    }
12752
12753    pub fn do_paste(
12754        &mut self,
12755        text: &String,
12756        clipboard_selections: Option<Vec<ClipboardSelection>>,
12757        handle_entire_lines: bool,
12758        window: &mut Window,
12759        cx: &mut Context<Self>,
12760    ) {
12761        if self.read_only(cx) {
12762            return;
12763        }
12764
12765        let clipboard_text = Cow::Borrowed(text.as_str());
12766
12767        self.transact(window, cx, |this, window, cx| {
12768            let had_active_edit_prediction = this.has_active_edit_prediction();
12769            let display_map = this.display_snapshot(cx);
12770            let old_selections = this.selections.all::<usize>(&display_map);
12771            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12772
12773            if let Some(mut clipboard_selections) = clipboard_selections {
12774                let all_selections_were_entire_line =
12775                    clipboard_selections.iter().all(|s| s.is_entire_line);
12776                let first_selection_indent_column =
12777                    clipboard_selections.first().map(|s| s.first_line_indent);
12778                if clipboard_selections.len() != old_selections.len() {
12779                    clipboard_selections.drain(..);
12780                }
12781                let mut auto_indent_on_paste = true;
12782
12783                this.buffer.update(cx, |buffer, cx| {
12784                    let snapshot = buffer.read(cx);
12785                    auto_indent_on_paste = snapshot
12786                        .language_settings_at(cursor_offset, cx)
12787                        .auto_indent_on_paste;
12788
12789                    let mut start_offset = 0;
12790                    let mut edits = Vec::new();
12791                    let mut original_indent_columns = Vec::new();
12792                    for (ix, selection) in old_selections.iter().enumerate() {
12793                        let to_insert;
12794                        let entire_line;
12795                        let original_indent_column;
12796                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12797                            let end_offset = start_offset + clipboard_selection.len;
12798                            to_insert = &clipboard_text[start_offset..end_offset];
12799                            entire_line = clipboard_selection.is_entire_line;
12800                            start_offset = end_offset + 1;
12801                            original_indent_column = Some(clipboard_selection.first_line_indent);
12802                        } else {
12803                            to_insert = &*clipboard_text;
12804                            entire_line = all_selections_were_entire_line;
12805                            original_indent_column = first_selection_indent_column
12806                        }
12807
12808                        let (range, to_insert) =
12809                            if selection.is_empty() && handle_entire_lines && entire_line {
12810                                // If the corresponding selection was empty when this slice of the
12811                                // clipboard text was written, then the entire line containing the
12812                                // selection was copied. If this selection is also currently empty,
12813                                // then paste the line before the current line of the buffer.
12814                                let column = selection.start.to_point(&snapshot).column as usize;
12815                                let line_start = selection.start - column;
12816                                (line_start..line_start, Cow::Borrowed(to_insert))
12817                            } else {
12818                                let language = snapshot.language_at(selection.head());
12819                                let range = selection.range();
12820                                if let Some(language) = language
12821                                    && language.name() == "Markdown".into()
12822                                {
12823                                    edit_for_markdown_paste(
12824                                        &snapshot,
12825                                        range,
12826                                        to_insert,
12827                                        url::Url::parse(to_insert).ok(),
12828                                    )
12829                                } else {
12830                                    (range, Cow::Borrowed(to_insert))
12831                                }
12832                            };
12833
12834                        edits.push((range, to_insert));
12835                        original_indent_columns.push(original_indent_column);
12836                    }
12837                    drop(snapshot);
12838
12839                    buffer.edit(
12840                        edits,
12841                        if auto_indent_on_paste {
12842                            Some(AutoindentMode::Block {
12843                                original_indent_columns,
12844                            })
12845                        } else {
12846                            None
12847                        },
12848                        cx,
12849                    );
12850                });
12851
12852                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12853                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12854            } else {
12855                let url = url::Url::parse(&clipboard_text).ok();
12856
12857                let auto_indent_mode = if !clipboard_text.is_empty() {
12858                    Some(AutoindentMode::Block {
12859                        original_indent_columns: Vec::new(),
12860                    })
12861                } else {
12862                    None
12863                };
12864
12865                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12866                    let snapshot = buffer.snapshot(cx);
12867
12868                    let anchors = old_selections
12869                        .iter()
12870                        .map(|s| {
12871                            let anchor = snapshot.anchor_after(s.head());
12872                            s.map(|_| anchor)
12873                        })
12874                        .collect::<Vec<_>>();
12875
12876                    let mut edits = Vec::new();
12877
12878                    for selection in old_selections.iter() {
12879                        let language = snapshot.language_at(selection.head());
12880                        let range = selection.range();
12881
12882                        let (edit_range, edit_text) = if let Some(language) = language
12883                            && language.name() == "Markdown".into()
12884                        {
12885                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12886                        } else {
12887                            (range, clipboard_text.clone())
12888                        };
12889
12890                        edits.push((edit_range, edit_text));
12891                    }
12892
12893                    drop(snapshot);
12894                    buffer.edit(edits, auto_indent_mode, cx);
12895
12896                    anchors
12897                });
12898
12899                this.change_selections(Default::default(), window, cx, |s| {
12900                    s.select_anchors(selection_anchors);
12901                });
12902            }
12903
12904            //   🤔                 |    ..     | show_in_menu |
12905            // | ..                  |   true        true
12906            // | had_edit_prediction |   false       true
12907
12908            let trigger_in_words =
12909                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12910
12911            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12912        });
12913    }
12914
12915    pub fn diff_clipboard_with_selection(
12916        &mut self,
12917        _: &DiffClipboardWithSelection,
12918        window: &mut Window,
12919        cx: &mut Context<Self>,
12920    ) {
12921        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12922
12923        if selections.is_empty() {
12924            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12925            return;
12926        };
12927
12928        let clipboard_text = match cx.read_from_clipboard() {
12929            Some(item) => match item.entries().first() {
12930                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12931                _ => None,
12932            },
12933            None => None,
12934        };
12935
12936        let Some(clipboard_text) = clipboard_text else {
12937            log::warn!("Clipboard doesn't contain text.");
12938            return;
12939        };
12940
12941        window.dispatch_action(
12942            Box::new(DiffClipboardWithSelectionData {
12943                clipboard_text,
12944                editor: cx.entity(),
12945            }),
12946            cx,
12947        );
12948    }
12949
12950    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12951        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12952        if let Some(item) = cx.read_from_clipboard() {
12953            let entries = item.entries();
12954
12955            match entries.first() {
12956                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12957                // of all the pasted entries.
12958                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12959                    .do_paste(
12960                        clipboard_string.text(),
12961                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12962                        true,
12963                        window,
12964                        cx,
12965                    ),
12966                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12967            }
12968        }
12969    }
12970
12971    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12972        if self.read_only(cx) {
12973            return;
12974        }
12975
12976        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12977
12978        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12979            if let Some((selections, _)) =
12980                self.selection_history.transaction(transaction_id).cloned()
12981            {
12982                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12983                    s.select_anchors(selections.to_vec());
12984                });
12985            } else {
12986                log::error!(
12987                    "No entry in selection_history found for undo. \
12988                     This may correspond to a bug where undo does not update the selection. \
12989                     If this is occurring, please add details to \
12990                     https://github.com/zed-industries/zed/issues/22692"
12991                );
12992            }
12993            self.request_autoscroll(Autoscroll::fit(), cx);
12994            self.unmark_text(window, cx);
12995            self.refresh_edit_prediction(true, false, window, cx);
12996            cx.emit(EditorEvent::Edited { transaction_id });
12997            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12998        }
12999    }
13000
13001    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13002        if self.read_only(cx) {
13003            return;
13004        }
13005
13006        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13007
13008        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13009            if let Some((_, Some(selections))) =
13010                self.selection_history.transaction(transaction_id).cloned()
13011            {
13012                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13013                    s.select_anchors(selections.to_vec());
13014                });
13015            } else {
13016                log::error!(
13017                    "No entry in selection_history found for redo. \
13018                     This may correspond to a bug where undo does not update the selection. \
13019                     If this is occurring, please add details to \
13020                     https://github.com/zed-industries/zed/issues/22692"
13021                );
13022            }
13023            self.request_autoscroll(Autoscroll::fit(), cx);
13024            self.unmark_text(window, cx);
13025            self.refresh_edit_prediction(true, false, window, cx);
13026            cx.emit(EditorEvent::Edited { transaction_id });
13027        }
13028    }
13029
13030    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13031        self.buffer
13032            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13033    }
13034
13035    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13036        self.buffer
13037            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13038    }
13039
13040    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13041        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13042        self.change_selections(Default::default(), window, cx, |s| {
13043            s.move_with(|map, selection| {
13044                let cursor = if selection.is_empty() {
13045                    movement::left(map, selection.start)
13046                } else {
13047                    selection.start
13048                };
13049                selection.collapse_to(cursor, SelectionGoal::None);
13050            });
13051        })
13052    }
13053
13054    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13055        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13056        self.change_selections(Default::default(), window, cx, |s| {
13057            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13058        })
13059    }
13060
13061    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13062        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13063        self.change_selections(Default::default(), window, cx, |s| {
13064            s.move_with(|map, selection| {
13065                let cursor = if selection.is_empty() {
13066                    movement::right(map, selection.end)
13067                } else {
13068                    selection.end
13069                };
13070                selection.collapse_to(cursor, SelectionGoal::None)
13071            });
13072        })
13073    }
13074
13075    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13076        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13077        self.change_selections(Default::default(), window, cx, |s| {
13078            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13079        });
13080    }
13081
13082    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13083        if self.take_rename(true, window, cx).is_some() {
13084            return;
13085        }
13086
13087        if self.mode.is_single_line() {
13088            cx.propagate();
13089            return;
13090        }
13091
13092        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13093
13094        let text_layout_details = &self.text_layout_details(window);
13095        let selection_count = self.selections.count();
13096        let first_selection = self.selections.first_anchor();
13097
13098        self.change_selections(Default::default(), window, cx, |s| {
13099            s.move_with(|map, selection| {
13100                if !selection.is_empty() {
13101                    selection.goal = SelectionGoal::None;
13102                }
13103                let (cursor, goal) = movement::up(
13104                    map,
13105                    selection.start,
13106                    selection.goal,
13107                    false,
13108                    text_layout_details,
13109                );
13110                selection.collapse_to(cursor, goal);
13111            });
13112        });
13113
13114        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13115        {
13116            cx.propagate();
13117        }
13118    }
13119
13120    pub fn move_up_by_lines(
13121        &mut self,
13122        action: &MoveUpByLines,
13123        window: &mut Window,
13124        cx: &mut Context<Self>,
13125    ) {
13126        if self.take_rename(true, window, cx).is_some() {
13127            return;
13128        }
13129
13130        if self.mode.is_single_line() {
13131            cx.propagate();
13132            return;
13133        }
13134
13135        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13136
13137        let text_layout_details = &self.text_layout_details(window);
13138
13139        self.change_selections(Default::default(), window, cx, |s| {
13140            s.move_with(|map, selection| {
13141                if !selection.is_empty() {
13142                    selection.goal = SelectionGoal::None;
13143                }
13144                let (cursor, goal) = movement::up_by_rows(
13145                    map,
13146                    selection.start,
13147                    action.lines,
13148                    selection.goal,
13149                    false,
13150                    text_layout_details,
13151                );
13152                selection.collapse_to(cursor, goal);
13153            });
13154        })
13155    }
13156
13157    pub fn move_down_by_lines(
13158        &mut self,
13159        action: &MoveDownByLines,
13160        window: &mut Window,
13161        cx: &mut Context<Self>,
13162    ) {
13163        if self.take_rename(true, window, cx).is_some() {
13164            return;
13165        }
13166
13167        if self.mode.is_single_line() {
13168            cx.propagate();
13169            return;
13170        }
13171
13172        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13173
13174        let text_layout_details = &self.text_layout_details(window);
13175
13176        self.change_selections(Default::default(), window, cx, |s| {
13177            s.move_with(|map, selection| {
13178                if !selection.is_empty() {
13179                    selection.goal = SelectionGoal::None;
13180                }
13181                let (cursor, goal) = movement::down_by_rows(
13182                    map,
13183                    selection.start,
13184                    action.lines,
13185                    selection.goal,
13186                    false,
13187                    text_layout_details,
13188                );
13189                selection.collapse_to(cursor, goal);
13190            });
13191        })
13192    }
13193
13194    pub fn select_down_by_lines(
13195        &mut self,
13196        action: &SelectDownByLines,
13197        window: &mut Window,
13198        cx: &mut Context<Self>,
13199    ) {
13200        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13201        let text_layout_details = &self.text_layout_details(window);
13202        self.change_selections(Default::default(), window, cx, |s| {
13203            s.move_heads_with(|map, head, goal| {
13204                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13205            })
13206        })
13207    }
13208
13209    pub fn select_up_by_lines(
13210        &mut self,
13211        action: &SelectUpByLines,
13212        window: &mut Window,
13213        cx: &mut Context<Self>,
13214    ) {
13215        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13216        let text_layout_details = &self.text_layout_details(window);
13217        self.change_selections(Default::default(), window, cx, |s| {
13218            s.move_heads_with(|map, head, goal| {
13219                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13220            })
13221        })
13222    }
13223
13224    pub fn select_page_up(
13225        &mut self,
13226        _: &SelectPageUp,
13227        window: &mut Window,
13228        cx: &mut Context<Self>,
13229    ) {
13230        let Some(row_count) = self.visible_row_count() else {
13231            return;
13232        };
13233
13234        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13235
13236        let text_layout_details = &self.text_layout_details(window);
13237
13238        self.change_selections(Default::default(), window, cx, |s| {
13239            s.move_heads_with(|map, head, goal| {
13240                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13241            })
13242        })
13243    }
13244
13245    pub fn move_page_up(
13246        &mut self,
13247        action: &MovePageUp,
13248        window: &mut Window,
13249        cx: &mut Context<Self>,
13250    ) {
13251        if self.take_rename(true, window, cx).is_some() {
13252            return;
13253        }
13254
13255        if self
13256            .context_menu
13257            .borrow_mut()
13258            .as_mut()
13259            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13260            .unwrap_or(false)
13261        {
13262            return;
13263        }
13264
13265        if matches!(self.mode, EditorMode::SingleLine) {
13266            cx.propagate();
13267            return;
13268        }
13269
13270        let Some(row_count) = self.visible_row_count() else {
13271            return;
13272        };
13273
13274        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13275
13276        let effects = if action.center_cursor {
13277            SelectionEffects::scroll(Autoscroll::center())
13278        } else {
13279            SelectionEffects::default()
13280        };
13281
13282        let text_layout_details = &self.text_layout_details(window);
13283
13284        self.change_selections(effects, window, cx, |s| {
13285            s.move_with(|map, selection| {
13286                if !selection.is_empty() {
13287                    selection.goal = SelectionGoal::None;
13288                }
13289                let (cursor, goal) = movement::up_by_rows(
13290                    map,
13291                    selection.end,
13292                    row_count,
13293                    selection.goal,
13294                    false,
13295                    text_layout_details,
13296                );
13297                selection.collapse_to(cursor, goal);
13298            });
13299        });
13300    }
13301
13302    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13303        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13304        let text_layout_details = &self.text_layout_details(window);
13305        self.change_selections(Default::default(), window, cx, |s| {
13306            s.move_heads_with(|map, head, goal| {
13307                movement::up(map, head, goal, false, text_layout_details)
13308            })
13309        })
13310    }
13311
13312    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13313        self.take_rename(true, window, cx);
13314
13315        if self.mode.is_single_line() {
13316            cx.propagate();
13317            return;
13318        }
13319
13320        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13321
13322        let text_layout_details = &self.text_layout_details(window);
13323        let selection_count = self.selections.count();
13324        let first_selection = self.selections.first_anchor();
13325
13326        self.change_selections(Default::default(), window, cx, |s| {
13327            s.move_with(|map, selection| {
13328                if !selection.is_empty() {
13329                    selection.goal = SelectionGoal::None;
13330                }
13331                let (cursor, goal) = movement::down(
13332                    map,
13333                    selection.end,
13334                    selection.goal,
13335                    false,
13336                    text_layout_details,
13337                );
13338                selection.collapse_to(cursor, goal);
13339            });
13340        });
13341
13342        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13343        {
13344            cx.propagate();
13345        }
13346    }
13347
13348    pub fn select_page_down(
13349        &mut self,
13350        _: &SelectPageDown,
13351        window: &mut Window,
13352        cx: &mut Context<Self>,
13353    ) {
13354        let Some(row_count) = self.visible_row_count() else {
13355            return;
13356        };
13357
13358        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13359
13360        let text_layout_details = &self.text_layout_details(window);
13361
13362        self.change_selections(Default::default(), window, cx, |s| {
13363            s.move_heads_with(|map, head, goal| {
13364                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13365            })
13366        })
13367    }
13368
13369    pub fn move_page_down(
13370        &mut self,
13371        action: &MovePageDown,
13372        window: &mut Window,
13373        cx: &mut Context<Self>,
13374    ) {
13375        if self.take_rename(true, window, cx).is_some() {
13376            return;
13377        }
13378
13379        if self
13380            .context_menu
13381            .borrow_mut()
13382            .as_mut()
13383            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13384            .unwrap_or(false)
13385        {
13386            return;
13387        }
13388
13389        if matches!(self.mode, EditorMode::SingleLine) {
13390            cx.propagate();
13391            return;
13392        }
13393
13394        let Some(row_count) = self.visible_row_count() else {
13395            return;
13396        };
13397
13398        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13399
13400        let effects = if action.center_cursor {
13401            SelectionEffects::scroll(Autoscroll::center())
13402        } else {
13403            SelectionEffects::default()
13404        };
13405
13406        let text_layout_details = &self.text_layout_details(window);
13407        self.change_selections(effects, window, cx, |s| {
13408            s.move_with(|map, selection| {
13409                if !selection.is_empty() {
13410                    selection.goal = SelectionGoal::None;
13411                }
13412                let (cursor, goal) = movement::down_by_rows(
13413                    map,
13414                    selection.end,
13415                    row_count,
13416                    selection.goal,
13417                    false,
13418                    text_layout_details,
13419                );
13420                selection.collapse_to(cursor, goal);
13421            });
13422        });
13423    }
13424
13425    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13426        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13427        let text_layout_details = &self.text_layout_details(window);
13428        self.change_selections(Default::default(), window, cx, |s| {
13429            s.move_heads_with(|map, head, goal| {
13430                movement::down(map, head, goal, false, text_layout_details)
13431            })
13432        });
13433    }
13434
13435    pub fn context_menu_first(
13436        &mut self,
13437        _: &ContextMenuFirst,
13438        window: &mut Window,
13439        cx: &mut Context<Self>,
13440    ) {
13441        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13442            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13443        }
13444    }
13445
13446    pub fn context_menu_prev(
13447        &mut self,
13448        _: &ContextMenuPrevious,
13449        window: &mut Window,
13450        cx: &mut Context<Self>,
13451    ) {
13452        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13453            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13454        }
13455    }
13456
13457    pub fn context_menu_next(
13458        &mut self,
13459        _: &ContextMenuNext,
13460        window: &mut Window,
13461        cx: &mut Context<Self>,
13462    ) {
13463        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13464            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13465        }
13466    }
13467
13468    pub fn context_menu_last(
13469        &mut self,
13470        _: &ContextMenuLast,
13471        window: &mut Window,
13472        cx: &mut Context<Self>,
13473    ) {
13474        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13475            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13476        }
13477    }
13478
13479    pub fn signature_help_prev(
13480        &mut self,
13481        _: &SignatureHelpPrevious,
13482        _: &mut Window,
13483        cx: &mut Context<Self>,
13484    ) {
13485        if let Some(popover) = self.signature_help_state.popover_mut() {
13486            if popover.current_signature == 0 {
13487                popover.current_signature = popover.signatures.len() - 1;
13488            } else {
13489                popover.current_signature -= 1;
13490            }
13491            cx.notify();
13492        }
13493    }
13494
13495    pub fn signature_help_next(
13496        &mut self,
13497        _: &SignatureHelpNext,
13498        _: &mut Window,
13499        cx: &mut Context<Self>,
13500    ) {
13501        if let Some(popover) = self.signature_help_state.popover_mut() {
13502            if popover.current_signature + 1 == popover.signatures.len() {
13503                popover.current_signature = 0;
13504            } else {
13505                popover.current_signature += 1;
13506            }
13507            cx.notify();
13508        }
13509    }
13510
13511    pub fn move_to_previous_word_start(
13512        &mut self,
13513        _: &MoveToPreviousWordStart,
13514        window: &mut Window,
13515        cx: &mut Context<Self>,
13516    ) {
13517        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13518        self.change_selections(Default::default(), window, cx, |s| {
13519            s.move_cursors_with(|map, head, _| {
13520                (
13521                    movement::previous_word_start(map, head),
13522                    SelectionGoal::None,
13523                )
13524            });
13525        })
13526    }
13527
13528    pub fn move_to_previous_subword_start(
13529        &mut self,
13530        _: &MoveToPreviousSubwordStart,
13531        window: &mut Window,
13532        cx: &mut Context<Self>,
13533    ) {
13534        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13535        self.change_selections(Default::default(), window, cx, |s| {
13536            s.move_cursors_with(|map, head, _| {
13537                (
13538                    movement::previous_subword_start(map, head),
13539                    SelectionGoal::None,
13540                )
13541            });
13542        })
13543    }
13544
13545    pub fn select_to_previous_word_start(
13546        &mut self,
13547        _: &SelectToPreviousWordStart,
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::previous_word_start(map, head),
13556                    SelectionGoal::None,
13557                )
13558            });
13559        })
13560    }
13561
13562    pub fn select_to_previous_subword_start(
13563        &mut self,
13564        _: &SelectToPreviousSubwordStart,
13565        window: &mut Window,
13566        cx: &mut Context<Self>,
13567    ) {
13568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13569        self.change_selections(Default::default(), window, cx, |s| {
13570            s.move_heads_with(|map, head, _| {
13571                (
13572                    movement::previous_subword_start(map, head),
13573                    SelectionGoal::None,
13574                )
13575            });
13576        })
13577    }
13578
13579    pub fn delete_to_previous_word_start(
13580        &mut self,
13581        action: &DeleteToPreviousWordStart,
13582        window: &mut Window,
13583        cx: &mut Context<Self>,
13584    ) {
13585        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13586        self.transact(window, cx, |this, window, cx| {
13587            this.select_autoclose_pair(window, cx);
13588            this.change_selections(Default::default(), window, cx, |s| {
13589                s.move_with(|map, selection| {
13590                    if selection.is_empty() {
13591                        let mut cursor = if action.ignore_newlines {
13592                            movement::previous_word_start(map, selection.head())
13593                        } else {
13594                            movement::previous_word_start_or_newline(map, selection.head())
13595                        };
13596                        cursor = movement::adjust_greedy_deletion(
13597                            map,
13598                            selection.head(),
13599                            cursor,
13600                            action.ignore_brackets,
13601                        );
13602                        selection.set_head(cursor, SelectionGoal::None);
13603                    }
13604                });
13605            });
13606            this.insert("", window, cx);
13607        });
13608    }
13609
13610    pub fn delete_to_previous_subword_start(
13611        &mut self,
13612        _: &DeleteToPreviousSubwordStart,
13613        window: &mut Window,
13614        cx: &mut Context<Self>,
13615    ) {
13616        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13617        self.transact(window, cx, |this, window, cx| {
13618            this.select_autoclose_pair(window, cx);
13619            this.change_selections(Default::default(), window, cx, |s| {
13620                s.move_with(|map, selection| {
13621                    if selection.is_empty() {
13622                        let mut cursor = movement::previous_subword_start(map, selection.head());
13623                        cursor =
13624                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13625                        selection.set_head(cursor, SelectionGoal::None);
13626                    }
13627                });
13628            });
13629            this.insert("", window, cx);
13630        });
13631    }
13632
13633    pub fn move_to_next_word_end(
13634        &mut self,
13635        _: &MoveToNextWordEnd,
13636        window: &mut Window,
13637        cx: &mut Context<Self>,
13638    ) {
13639        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13640        self.change_selections(Default::default(), window, cx, |s| {
13641            s.move_cursors_with(|map, head, _| {
13642                (movement::next_word_end(map, head), SelectionGoal::None)
13643            });
13644        })
13645    }
13646
13647    pub fn move_to_next_subword_end(
13648        &mut self,
13649        _: &MoveToNextSubwordEnd,
13650        window: &mut Window,
13651        cx: &mut Context<Self>,
13652    ) {
13653        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13654        self.change_selections(Default::default(), window, cx, |s| {
13655            s.move_cursors_with(|map, head, _| {
13656                (movement::next_subword_end(map, head), SelectionGoal::None)
13657            });
13658        })
13659    }
13660
13661    pub fn select_to_next_word_end(
13662        &mut self,
13663        _: &SelectToNextWordEnd,
13664        window: &mut Window,
13665        cx: &mut Context<Self>,
13666    ) {
13667        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13668        self.change_selections(Default::default(), window, cx, |s| {
13669            s.move_heads_with(|map, head, _| {
13670                (movement::next_word_end(map, head), SelectionGoal::None)
13671            });
13672        })
13673    }
13674
13675    pub fn select_to_next_subword_end(
13676        &mut self,
13677        _: &SelectToNextSubwordEnd,
13678        window: &mut Window,
13679        cx: &mut Context<Self>,
13680    ) {
13681        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13682        self.change_selections(Default::default(), window, cx, |s| {
13683            s.move_heads_with(|map, head, _| {
13684                (movement::next_subword_end(map, head), SelectionGoal::None)
13685            });
13686        })
13687    }
13688
13689    pub fn delete_to_next_word_end(
13690        &mut self,
13691        action: &DeleteToNextWordEnd,
13692        window: &mut Window,
13693        cx: &mut Context<Self>,
13694    ) {
13695        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13696        self.transact(window, cx, |this, window, cx| {
13697            this.change_selections(Default::default(), window, cx, |s| {
13698                s.move_with(|map, selection| {
13699                    if selection.is_empty() {
13700                        let mut cursor = if action.ignore_newlines {
13701                            movement::next_word_end(map, selection.head())
13702                        } else {
13703                            movement::next_word_end_or_newline(map, selection.head())
13704                        };
13705                        cursor = movement::adjust_greedy_deletion(
13706                            map,
13707                            selection.head(),
13708                            cursor,
13709                            action.ignore_brackets,
13710                        );
13711                        selection.set_head(cursor, SelectionGoal::None);
13712                    }
13713                });
13714            });
13715            this.insert("", window, cx);
13716        });
13717    }
13718
13719    pub fn delete_to_next_subword_end(
13720        &mut self,
13721        _: &DeleteToNextSubwordEnd,
13722        window: &mut Window,
13723        cx: &mut Context<Self>,
13724    ) {
13725        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13726        self.transact(window, cx, |this, window, cx| {
13727            this.change_selections(Default::default(), window, cx, |s| {
13728                s.move_with(|map, selection| {
13729                    if selection.is_empty() {
13730                        let mut cursor = movement::next_subword_end(map, selection.head());
13731                        cursor =
13732                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13733                        selection.set_head(cursor, SelectionGoal::None);
13734                    }
13735                });
13736            });
13737            this.insert("", window, cx);
13738        });
13739    }
13740
13741    pub fn move_to_beginning_of_line(
13742        &mut self,
13743        action: &MoveToBeginningOfLine,
13744        window: &mut Window,
13745        cx: &mut Context<Self>,
13746    ) {
13747        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13748        self.change_selections(Default::default(), window, cx, |s| {
13749            s.move_cursors_with(|map, head, _| {
13750                (
13751                    movement::indented_line_beginning(
13752                        map,
13753                        head,
13754                        action.stop_at_soft_wraps,
13755                        action.stop_at_indent,
13756                    ),
13757                    SelectionGoal::None,
13758                )
13759            });
13760        })
13761    }
13762
13763    pub fn select_to_beginning_of_line(
13764        &mut self,
13765        action: &SelectToBeginningOfLine,
13766        window: &mut Window,
13767        cx: &mut Context<Self>,
13768    ) {
13769        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13770        self.change_selections(Default::default(), window, cx, |s| {
13771            s.move_heads_with(|map, head, _| {
13772                (
13773                    movement::indented_line_beginning(
13774                        map,
13775                        head,
13776                        action.stop_at_soft_wraps,
13777                        action.stop_at_indent,
13778                    ),
13779                    SelectionGoal::None,
13780                )
13781            });
13782        });
13783    }
13784
13785    pub fn delete_to_beginning_of_line(
13786        &mut self,
13787        action: &DeleteToBeginningOfLine,
13788        window: &mut Window,
13789        cx: &mut Context<Self>,
13790    ) {
13791        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13792        self.transact(window, cx, |this, window, cx| {
13793            this.change_selections(Default::default(), window, cx, |s| {
13794                s.move_with(|_, selection| {
13795                    selection.reversed = true;
13796                });
13797            });
13798
13799            this.select_to_beginning_of_line(
13800                &SelectToBeginningOfLine {
13801                    stop_at_soft_wraps: false,
13802                    stop_at_indent: action.stop_at_indent,
13803                },
13804                window,
13805                cx,
13806            );
13807            this.backspace(&Backspace, window, cx);
13808        });
13809    }
13810
13811    pub fn move_to_end_of_line(
13812        &mut self,
13813        action: &MoveToEndOfLine,
13814        window: &mut Window,
13815        cx: &mut Context<Self>,
13816    ) {
13817        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13818        self.change_selections(Default::default(), window, cx, |s| {
13819            s.move_cursors_with(|map, head, _| {
13820                (
13821                    movement::line_end(map, head, action.stop_at_soft_wraps),
13822                    SelectionGoal::None,
13823                )
13824            });
13825        })
13826    }
13827
13828    pub fn select_to_end_of_line(
13829        &mut self,
13830        action: &SelectToEndOfLine,
13831        window: &mut Window,
13832        cx: &mut Context<Self>,
13833    ) {
13834        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13835        self.change_selections(Default::default(), window, cx, |s| {
13836            s.move_heads_with(|map, head, _| {
13837                (
13838                    movement::line_end(map, head, action.stop_at_soft_wraps),
13839                    SelectionGoal::None,
13840                )
13841            });
13842        })
13843    }
13844
13845    pub fn delete_to_end_of_line(
13846        &mut self,
13847        _: &DeleteToEndOfLine,
13848        window: &mut Window,
13849        cx: &mut Context<Self>,
13850    ) {
13851        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13852        self.transact(window, cx, |this, window, cx| {
13853            this.select_to_end_of_line(
13854                &SelectToEndOfLine {
13855                    stop_at_soft_wraps: false,
13856                },
13857                window,
13858                cx,
13859            );
13860            this.delete(&Delete, window, cx);
13861        });
13862    }
13863
13864    pub fn cut_to_end_of_line(
13865        &mut self,
13866        action: &CutToEndOfLine,
13867        window: &mut Window,
13868        cx: &mut Context<Self>,
13869    ) {
13870        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13871        self.transact(window, cx, |this, window, cx| {
13872            this.select_to_end_of_line(
13873                &SelectToEndOfLine {
13874                    stop_at_soft_wraps: false,
13875                },
13876                window,
13877                cx,
13878            );
13879            if !action.stop_at_newlines {
13880                this.change_selections(Default::default(), window, cx, |s| {
13881                    s.move_with(|_, sel| {
13882                        if sel.is_empty() {
13883                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13884                        }
13885                    });
13886                });
13887            }
13888            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13889            let item = this.cut_common(false, window, cx);
13890            cx.write_to_clipboard(item);
13891        });
13892    }
13893
13894    pub fn move_to_start_of_paragraph(
13895        &mut self,
13896        _: &MoveToStartOfParagraph,
13897        window: &mut Window,
13898        cx: &mut Context<Self>,
13899    ) {
13900        if matches!(self.mode, EditorMode::SingleLine) {
13901            cx.propagate();
13902            return;
13903        }
13904        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13905        self.change_selections(Default::default(), window, cx, |s| {
13906            s.move_with(|map, selection| {
13907                selection.collapse_to(
13908                    movement::start_of_paragraph(map, selection.head(), 1),
13909                    SelectionGoal::None,
13910                )
13911            });
13912        })
13913    }
13914
13915    pub fn move_to_end_of_paragraph(
13916        &mut self,
13917        _: &MoveToEndOfParagraph,
13918        window: &mut Window,
13919        cx: &mut Context<Self>,
13920    ) {
13921        if matches!(self.mode, EditorMode::SingleLine) {
13922            cx.propagate();
13923            return;
13924        }
13925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13926        self.change_selections(Default::default(), window, cx, |s| {
13927            s.move_with(|map, selection| {
13928                selection.collapse_to(
13929                    movement::end_of_paragraph(map, selection.head(), 1),
13930                    SelectionGoal::None,
13931                )
13932            });
13933        })
13934    }
13935
13936    pub fn select_to_start_of_paragraph(
13937        &mut self,
13938        _: &SelectToStartOfParagraph,
13939        window: &mut Window,
13940        cx: &mut Context<Self>,
13941    ) {
13942        if matches!(self.mode, EditorMode::SingleLine) {
13943            cx.propagate();
13944            return;
13945        }
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13947        self.change_selections(Default::default(), window, cx, |s| {
13948            s.move_heads_with(|map, head, _| {
13949                (
13950                    movement::start_of_paragraph(map, head, 1),
13951                    SelectionGoal::None,
13952                )
13953            });
13954        })
13955    }
13956
13957    pub fn select_to_end_of_paragraph(
13958        &mut self,
13959        _: &SelectToEndOfParagraph,
13960        window: &mut Window,
13961        cx: &mut Context<Self>,
13962    ) {
13963        if matches!(self.mode, EditorMode::SingleLine) {
13964            cx.propagate();
13965            return;
13966        }
13967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13968        self.change_selections(Default::default(), window, cx, |s| {
13969            s.move_heads_with(|map, head, _| {
13970                (
13971                    movement::end_of_paragraph(map, head, 1),
13972                    SelectionGoal::None,
13973                )
13974            });
13975        })
13976    }
13977
13978    pub fn move_to_start_of_excerpt(
13979        &mut self,
13980        _: &MoveToStartOfExcerpt,
13981        window: &mut Window,
13982        cx: &mut Context<Self>,
13983    ) {
13984        if matches!(self.mode, EditorMode::SingleLine) {
13985            cx.propagate();
13986            return;
13987        }
13988        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13989        self.change_selections(Default::default(), window, cx, |s| {
13990            s.move_with(|map, selection| {
13991                selection.collapse_to(
13992                    movement::start_of_excerpt(
13993                        map,
13994                        selection.head(),
13995                        workspace::searchable::Direction::Prev,
13996                    ),
13997                    SelectionGoal::None,
13998                )
13999            });
14000        })
14001    }
14002
14003    pub fn move_to_start_of_next_excerpt(
14004        &mut self,
14005        _: &MoveToStartOfNextExcerpt,
14006        window: &mut Window,
14007        cx: &mut Context<Self>,
14008    ) {
14009        if matches!(self.mode, EditorMode::SingleLine) {
14010            cx.propagate();
14011            return;
14012        }
14013
14014        self.change_selections(Default::default(), window, cx, |s| {
14015            s.move_with(|map, selection| {
14016                selection.collapse_to(
14017                    movement::start_of_excerpt(
14018                        map,
14019                        selection.head(),
14020                        workspace::searchable::Direction::Next,
14021                    ),
14022                    SelectionGoal::None,
14023                )
14024            });
14025        })
14026    }
14027
14028    pub fn move_to_end_of_excerpt(
14029        &mut self,
14030        _: &MoveToEndOfExcerpt,
14031        window: &mut Window,
14032        cx: &mut Context<Self>,
14033    ) {
14034        if matches!(self.mode, EditorMode::SingleLine) {
14035            cx.propagate();
14036            return;
14037        }
14038        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14039        self.change_selections(Default::default(), window, cx, |s| {
14040            s.move_with(|map, selection| {
14041                selection.collapse_to(
14042                    movement::end_of_excerpt(
14043                        map,
14044                        selection.head(),
14045                        workspace::searchable::Direction::Next,
14046                    ),
14047                    SelectionGoal::None,
14048                )
14049            });
14050        })
14051    }
14052
14053    pub fn move_to_end_of_previous_excerpt(
14054        &mut self,
14055        _: &MoveToEndOfPreviousExcerpt,
14056        window: &mut Window,
14057        cx: &mut Context<Self>,
14058    ) {
14059        if matches!(self.mode, EditorMode::SingleLine) {
14060            cx.propagate();
14061            return;
14062        }
14063        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14064        self.change_selections(Default::default(), window, cx, |s| {
14065            s.move_with(|map, selection| {
14066                selection.collapse_to(
14067                    movement::end_of_excerpt(
14068                        map,
14069                        selection.head(),
14070                        workspace::searchable::Direction::Prev,
14071                    ),
14072                    SelectionGoal::None,
14073                )
14074            });
14075        })
14076    }
14077
14078    pub fn select_to_start_of_excerpt(
14079        &mut self,
14080        _: &SelectToStartOfExcerpt,
14081        window: &mut Window,
14082        cx: &mut Context<Self>,
14083    ) {
14084        if matches!(self.mode, EditorMode::SingleLine) {
14085            cx.propagate();
14086            return;
14087        }
14088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14089        self.change_selections(Default::default(), window, cx, |s| {
14090            s.move_heads_with(|map, head, _| {
14091                (
14092                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14093                    SelectionGoal::None,
14094                )
14095            });
14096        })
14097    }
14098
14099    pub fn select_to_start_of_next_excerpt(
14100        &mut self,
14101        _: &SelectToStartOfNextExcerpt,
14102        window: &mut Window,
14103        cx: &mut Context<Self>,
14104    ) {
14105        if matches!(self.mode, EditorMode::SingleLine) {
14106            cx.propagate();
14107            return;
14108        }
14109        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14110        self.change_selections(Default::default(), window, cx, |s| {
14111            s.move_heads_with(|map, head, _| {
14112                (
14113                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14114                    SelectionGoal::None,
14115                )
14116            });
14117        })
14118    }
14119
14120    pub fn select_to_end_of_excerpt(
14121        &mut self,
14122        _: &SelectToEndOfExcerpt,
14123        window: &mut Window,
14124        cx: &mut Context<Self>,
14125    ) {
14126        if matches!(self.mode, EditorMode::SingleLine) {
14127            cx.propagate();
14128            return;
14129        }
14130        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14131        self.change_selections(Default::default(), window, cx, |s| {
14132            s.move_heads_with(|map, head, _| {
14133                (
14134                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14135                    SelectionGoal::None,
14136                )
14137            });
14138        })
14139    }
14140
14141    pub fn select_to_end_of_previous_excerpt(
14142        &mut self,
14143        _: &SelectToEndOfPreviousExcerpt,
14144        window: &mut Window,
14145        cx: &mut Context<Self>,
14146    ) {
14147        if matches!(self.mode, EditorMode::SingleLine) {
14148            cx.propagate();
14149            return;
14150        }
14151        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14152        self.change_selections(Default::default(), window, cx, |s| {
14153            s.move_heads_with(|map, head, _| {
14154                (
14155                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14156                    SelectionGoal::None,
14157                )
14158            });
14159        })
14160    }
14161
14162    pub fn move_to_beginning(
14163        &mut self,
14164        _: &MoveToBeginning,
14165        window: &mut Window,
14166        cx: &mut Context<Self>,
14167    ) {
14168        if matches!(self.mode, EditorMode::SingleLine) {
14169            cx.propagate();
14170            return;
14171        }
14172        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14173        self.change_selections(Default::default(), window, cx, |s| {
14174            s.select_ranges(vec![0..0]);
14175        });
14176    }
14177
14178    pub fn select_to_beginning(
14179        &mut self,
14180        _: &SelectToBeginning,
14181        window: &mut Window,
14182        cx: &mut Context<Self>,
14183    ) {
14184        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14185        selection.set_head(Point::zero(), SelectionGoal::None);
14186        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14187        self.change_selections(Default::default(), window, cx, |s| {
14188            s.select(vec![selection]);
14189        });
14190    }
14191
14192    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14193        if matches!(self.mode, EditorMode::SingleLine) {
14194            cx.propagate();
14195            return;
14196        }
14197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14198        let cursor = self.buffer.read(cx).read(cx).len();
14199        self.change_selections(Default::default(), window, cx, |s| {
14200            s.select_ranges(vec![cursor..cursor])
14201        });
14202    }
14203
14204    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14205        self.nav_history = nav_history;
14206    }
14207
14208    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14209        self.nav_history.as_ref()
14210    }
14211
14212    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14213        self.push_to_nav_history(
14214            self.selections.newest_anchor().head(),
14215            None,
14216            false,
14217            true,
14218            cx,
14219        );
14220    }
14221
14222    fn push_to_nav_history(
14223        &mut self,
14224        cursor_anchor: Anchor,
14225        new_position: Option<Point>,
14226        is_deactivate: bool,
14227        always: bool,
14228        cx: &mut Context<Self>,
14229    ) {
14230        if let Some(nav_history) = self.nav_history.as_mut() {
14231            let buffer = self.buffer.read(cx).read(cx);
14232            let cursor_position = cursor_anchor.to_point(&buffer);
14233            let scroll_state = self.scroll_manager.anchor();
14234            let scroll_top_row = scroll_state.top_row(&buffer);
14235            drop(buffer);
14236
14237            if let Some(new_position) = new_position {
14238                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14239                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14240                    return;
14241                }
14242            }
14243
14244            nav_history.push(
14245                Some(NavigationData {
14246                    cursor_anchor,
14247                    cursor_position,
14248                    scroll_anchor: scroll_state,
14249                    scroll_top_row,
14250                }),
14251                cx,
14252            );
14253            cx.emit(EditorEvent::PushedToNavHistory {
14254                anchor: cursor_anchor,
14255                is_deactivate,
14256            })
14257        }
14258    }
14259
14260    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14261        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14262        let buffer = self.buffer.read(cx).snapshot(cx);
14263        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14264        selection.set_head(buffer.len(), SelectionGoal::None);
14265        self.change_selections(Default::default(), window, cx, |s| {
14266            s.select(vec![selection]);
14267        });
14268    }
14269
14270    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14271        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14272        let end = self.buffer.read(cx).read(cx).len();
14273        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14274            s.select_ranges(vec![0..end]);
14275        });
14276    }
14277
14278    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14279        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14280        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14281        let mut selections = self.selections.all::<Point>(&display_map);
14282        let max_point = display_map.buffer_snapshot().max_point();
14283        for selection in &mut selections {
14284            let rows = selection.spanned_rows(true, &display_map);
14285            selection.start = Point::new(rows.start.0, 0);
14286            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14287            selection.reversed = false;
14288        }
14289        self.change_selections(Default::default(), window, cx, |s| {
14290            s.select(selections);
14291        });
14292    }
14293
14294    pub fn split_selection_into_lines(
14295        &mut self,
14296        action: &SplitSelectionIntoLines,
14297        window: &mut Window,
14298        cx: &mut Context<Self>,
14299    ) {
14300        let selections = self
14301            .selections
14302            .all::<Point>(&self.display_snapshot(cx))
14303            .into_iter()
14304            .map(|selection| selection.start..selection.end)
14305            .collect::<Vec<_>>();
14306        self.unfold_ranges(&selections, true, true, cx);
14307
14308        let mut new_selection_ranges = Vec::new();
14309        {
14310            let buffer = self.buffer.read(cx).read(cx);
14311            for selection in selections {
14312                for row in selection.start.row..selection.end.row {
14313                    let line_start = Point::new(row, 0);
14314                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14315
14316                    if action.keep_selections {
14317                        // Keep the selection range for each line
14318                        let selection_start = if row == selection.start.row {
14319                            selection.start
14320                        } else {
14321                            line_start
14322                        };
14323                        new_selection_ranges.push(selection_start..line_end);
14324                    } else {
14325                        // Collapse to cursor at end of line
14326                        new_selection_ranges.push(line_end..line_end);
14327                    }
14328                }
14329
14330                let is_multiline_selection = selection.start.row != selection.end.row;
14331                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14332                // so this action feels more ergonomic when paired with other selection operations
14333                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14334                if !should_skip_last {
14335                    if action.keep_selections {
14336                        if is_multiline_selection {
14337                            let line_start = Point::new(selection.end.row, 0);
14338                            new_selection_ranges.push(line_start..selection.end);
14339                        } else {
14340                            new_selection_ranges.push(selection.start..selection.end);
14341                        }
14342                    } else {
14343                        new_selection_ranges.push(selection.end..selection.end);
14344                    }
14345                }
14346            }
14347        }
14348        self.change_selections(Default::default(), window, cx, |s| {
14349            s.select_ranges(new_selection_ranges);
14350        });
14351    }
14352
14353    pub fn add_selection_above(
14354        &mut self,
14355        action: &AddSelectionAbove,
14356        window: &mut Window,
14357        cx: &mut Context<Self>,
14358    ) {
14359        self.add_selection(true, action.skip_soft_wrap, window, cx);
14360    }
14361
14362    pub fn add_selection_below(
14363        &mut self,
14364        action: &AddSelectionBelow,
14365        window: &mut Window,
14366        cx: &mut Context<Self>,
14367    ) {
14368        self.add_selection(false, action.skip_soft_wrap, window, cx);
14369    }
14370
14371    fn add_selection(
14372        &mut self,
14373        above: bool,
14374        skip_soft_wrap: bool,
14375        window: &mut Window,
14376        cx: &mut Context<Self>,
14377    ) {
14378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14379
14380        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14381        let all_selections = self.selections.all::<Point>(&display_map);
14382        let text_layout_details = self.text_layout_details(window);
14383
14384        let (mut columnar_selections, new_selections_to_columnarize) = {
14385            if let Some(state) = self.add_selections_state.as_ref() {
14386                let columnar_selection_ids: HashSet<_> = state
14387                    .groups
14388                    .iter()
14389                    .flat_map(|group| group.stack.iter())
14390                    .copied()
14391                    .collect();
14392
14393                all_selections
14394                    .into_iter()
14395                    .partition(|s| columnar_selection_ids.contains(&s.id))
14396            } else {
14397                (Vec::new(), all_selections)
14398            }
14399        };
14400
14401        let mut state = self
14402            .add_selections_state
14403            .take()
14404            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14405
14406        for selection in new_selections_to_columnarize {
14407            let range = selection.display_range(&display_map).sorted();
14408            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14409            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14410            let positions = start_x.min(end_x)..start_x.max(end_x);
14411            let mut stack = Vec::new();
14412            for row in range.start.row().0..=range.end.row().0 {
14413                if let Some(selection) = self.selections.build_columnar_selection(
14414                    &display_map,
14415                    DisplayRow(row),
14416                    &positions,
14417                    selection.reversed,
14418                    &text_layout_details,
14419                ) {
14420                    stack.push(selection.id);
14421                    columnar_selections.push(selection);
14422                }
14423            }
14424            if !stack.is_empty() {
14425                if above {
14426                    stack.reverse();
14427                }
14428                state.groups.push(AddSelectionsGroup { above, stack });
14429            }
14430        }
14431
14432        let mut final_selections = Vec::new();
14433        let end_row = if above {
14434            DisplayRow(0)
14435        } else {
14436            display_map.max_point().row()
14437        };
14438
14439        let mut last_added_item_per_group = HashMap::default();
14440        for group in state.groups.iter_mut() {
14441            if let Some(last_id) = group.stack.last() {
14442                last_added_item_per_group.insert(*last_id, group);
14443            }
14444        }
14445
14446        for selection in columnar_selections {
14447            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14448                if above == group.above {
14449                    let range = selection.display_range(&display_map).sorted();
14450                    debug_assert_eq!(range.start.row(), range.end.row());
14451                    let mut row = range.start.row();
14452                    let positions =
14453                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14454                            Pixels::from(start)..Pixels::from(end)
14455                        } else {
14456                            let start_x =
14457                                display_map.x_for_display_point(range.start, &text_layout_details);
14458                            let end_x =
14459                                display_map.x_for_display_point(range.end, &text_layout_details);
14460                            start_x.min(end_x)..start_x.max(end_x)
14461                        };
14462
14463                    let mut maybe_new_selection = None;
14464                    let direction = if above { -1 } else { 1 };
14465
14466                    while row != end_row {
14467                        if skip_soft_wrap {
14468                            row = display_map
14469                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14470                                .row();
14471                        } else if above {
14472                            row.0 -= 1;
14473                        } else {
14474                            row.0 += 1;
14475                        }
14476
14477                        if let Some(new_selection) = self.selections.build_columnar_selection(
14478                            &display_map,
14479                            row,
14480                            &positions,
14481                            selection.reversed,
14482                            &text_layout_details,
14483                        ) {
14484                            maybe_new_selection = Some(new_selection);
14485                            break;
14486                        }
14487                    }
14488
14489                    if let Some(new_selection) = maybe_new_selection {
14490                        group.stack.push(new_selection.id);
14491                        if above {
14492                            final_selections.push(new_selection);
14493                            final_selections.push(selection);
14494                        } else {
14495                            final_selections.push(selection);
14496                            final_selections.push(new_selection);
14497                        }
14498                    } else {
14499                        final_selections.push(selection);
14500                    }
14501                } else {
14502                    group.stack.pop();
14503                }
14504            } else {
14505                final_selections.push(selection);
14506            }
14507        }
14508
14509        self.change_selections(Default::default(), window, cx, |s| {
14510            s.select(final_selections);
14511        });
14512
14513        let final_selection_ids: HashSet<_> = self
14514            .selections
14515            .all::<Point>(&display_map)
14516            .iter()
14517            .map(|s| s.id)
14518            .collect();
14519        state.groups.retain_mut(|group| {
14520            // selections might get merged above so we remove invalid items from stacks
14521            group.stack.retain(|id| final_selection_ids.contains(id));
14522
14523            // single selection in stack can be treated as initial state
14524            group.stack.len() > 1
14525        });
14526
14527        if !state.groups.is_empty() {
14528            self.add_selections_state = Some(state);
14529        }
14530    }
14531
14532    fn select_match_ranges(
14533        &mut self,
14534        range: Range<usize>,
14535        reversed: bool,
14536        replace_newest: bool,
14537        auto_scroll: Option<Autoscroll>,
14538        window: &mut Window,
14539        cx: &mut Context<Editor>,
14540    ) {
14541        self.unfold_ranges(
14542            std::slice::from_ref(&range),
14543            false,
14544            auto_scroll.is_some(),
14545            cx,
14546        );
14547        let effects = if let Some(scroll) = auto_scroll {
14548            SelectionEffects::scroll(scroll)
14549        } else {
14550            SelectionEffects::no_scroll()
14551        };
14552        self.change_selections(effects, window, cx, |s| {
14553            if replace_newest {
14554                s.delete(s.newest_anchor().id);
14555            }
14556            if reversed {
14557                s.insert_range(range.end..range.start);
14558            } else {
14559                s.insert_range(range);
14560            }
14561        });
14562    }
14563
14564    pub fn select_next_match_internal(
14565        &mut self,
14566        display_map: &DisplaySnapshot,
14567        replace_newest: bool,
14568        autoscroll: Option<Autoscroll>,
14569        window: &mut Window,
14570        cx: &mut Context<Self>,
14571    ) -> Result<()> {
14572        let buffer = display_map.buffer_snapshot();
14573        let mut selections = self.selections.all::<usize>(&display_map);
14574        if let Some(mut select_next_state) = self.select_next_state.take() {
14575            let query = &select_next_state.query;
14576            if !select_next_state.done {
14577                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14578                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14579                let mut next_selected_range = None;
14580
14581                let bytes_after_last_selection =
14582                    buffer.bytes_in_range(last_selection.end..buffer.len());
14583                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14584                let query_matches = query
14585                    .stream_find_iter(bytes_after_last_selection)
14586                    .map(|result| (last_selection.end, result))
14587                    .chain(
14588                        query
14589                            .stream_find_iter(bytes_before_first_selection)
14590                            .map(|result| (0, result)),
14591                    );
14592
14593                for (start_offset, query_match) in query_matches {
14594                    let query_match = query_match.unwrap(); // can only fail due to I/O
14595                    let offset_range =
14596                        start_offset + query_match.start()..start_offset + query_match.end();
14597
14598                    if !select_next_state.wordwise
14599                        || (!buffer.is_inside_word(offset_range.start, None)
14600                            && !buffer.is_inside_word(offset_range.end, None))
14601                    {
14602                        let idx = selections
14603                            .partition_point(|selection| selection.end <= offset_range.start);
14604                        let overlaps = selections
14605                            .get(idx)
14606                            .map_or(false, |selection| selection.start < offset_range.end);
14607
14608                        if !overlaps {
14609                            next_selected_range = Some(offset_range);
14610                            break;
14611                        }
14612                    }
14613                }
14614
14615                if let Some(next_selected_range) = next_selected_range {
14616                    self.select_match_ranges(
14617                        next_selected_range,
14618                        last_selection.reversed,
14619                        replace_newest,
14620                        autoscroll,
14621                        window,
14622                        cx,
14623                    );
14624                } else {
14625                    select_next_state.done = true;
14626                }
14627            }
14628
14629            self.select_next_state = Some(select_next_state);
14630        } else {
14631            let mut only_carets = true;
14632            let mut same_text_selected = true;
14633            let mut selected_text = None;
14634
14635            let mut selections_iter = selections.iter().peekable();
14636            while let Some(selection) = selections_iter.next() {
14637                if selection.start != selection.end {
14638                    only_carets = false;
14639                }
14640
14641                if same_text_selected {
14642                    if selected_text.is_none() {
14643                        selected_text =
14644                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14645                    }
14646
14647                    if let Some(next_selection) = selections_iter.peek() {
14648                        if next_selection.range().len() == selection.range().len() {
14649                            let next_selected_text = buffer
14650                                .text_for_range(next_selection.range())
14651                                .collect::<String>();
14652                            if Some(next_selected_text) != selected_text {
14653                                same_text_selected = false;
14654                                selected_text = None;
14655                            }
14656                        } else {
14657                            same_text_selected = false;
14658                            selected_text = None;
14659                        }
14660                    }
14661                }
14662            }
14663
14664            if only_carets {
14665                for selection in &mut selections {
14666                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14667                    selection.start = word_range.start;
14668                    selection.end = word_range.end;
14669                    selection.goal = SelectionGoal::None;
14670                    selection.reversed = false;
14671                    self.select_match_ranges(
14672                        selection.start..selection.end,
14673                        selection.reversed,
14674                        replace_newest,
14675                        autoscroll,
14676                        window,
14677                        cx,
14678                    );
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: self.build_query(&[query], cx)?,
14691                        wordwise: true,
14692                        done: is_empty,
14693                    };
14694                    self.select_next_state = Some(select_state);
14695                } else {
14696                    self.select_next_state = None;
14697                }
14698            } else if let Some(selected_text) = selected_text {
14699                self.select_next_state = Some(SelectNextState {
14700                    query: self.build_query(&[selected_text], cx)?,
14701                    wordwise: false,
14702                    done: false,
14703                });
14704                self.select_next_match_internal(
14705                    display_map,
14706                    replace_newest,
14707                    autoscroll,
14708                    window,
14709                    cx,
14710                )?;
14711            }
14712        }
14713        Ok(())
14714    }
14715
14716    pub fn select_all_matches(
14717        &mut self,
14718        _action: &SelectAllMatches,
14719        window: &mut Window,
14720        cx: &mut Context<Self>,
14721    ) -> Result<()> {
14722        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14723
14724        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14725
14726        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14727        let Some(select_next_state) = self.select_next_state.as_mut() else {
14728            return Ok(());
14729        };
14730        if select_next_state.done {
14731            return Ok(());
14732        }
14733
14734        let mut new_selections = Vec::new();
14735
14736        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14737        let buffer = display_map.buffer_snapshot();
14738        let query_matches = select_next_state
14739            .query
14740            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14741
14742        for query_match in query_matches.into_iter() {
14743            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14744            let offset_range = if reversed {
14745                query_match.end()..query_match.start()
14746            } else {
14747                query_match.start()..query_match.end()
14748            };
14749
14750            if !select_next_state.wordwise
14751                || (!buffer.is_inside_word(offset_range.start, None)
14752                    && !buffer.is_inside_word(offset_range.end, None))
14753            {
14754                new_selections.push(offset_range.start..offset_range.end);
14755            }
14756        }
14757
14758        select_next_state.done = true;
14759
14760        if new_selections.is_empty() {
14761            log::error!("bug: new_selections is empty in select_all_matches");
14762            return Ok(());
14763        }
14764
14765        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14766        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14767            selections.select_ranges(new_selections)
14768        });
14769
14770        Ok(())
14771    }
14772
14773    pub fn select_next(
14774        &mut self,
14775        action: &SelectNext,
14776        window: &mut Window,
14777        cx: &mut Context<Self>,
14778    ) -> Result<()> {
14779        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14780        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14781        self.select_next_match_internal(
14782            &display_map,
14783            action.replace_newest,
14784            Some(Autoscroll::newest()),
14785            window,
14786            cx,
14787        )?;
14788        Ok(())
14789    }
14790
14791    pub fn select_previous(
14792        &mut self,
14793        action: &SelectPrevious,
14794        window: &mut Window,
14795        cx: &mut Context<Self>,
14796    ) -> Result<()> {
14797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14798        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14799        let buffer = display_map.buffer_snapshot();
14800        let mut selections = self.selections.all::<usize>(&display_map);
14801        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14802            let query = &select_prev_state.query;
14803            if !select_prev_state.done {
14804                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14805                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14806                let mut next_selected_range = None;
14807                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14808                let bytes_before_last_selection =
14809                    buffer.reversed_bytes_in_range(0..last_selection.start);
14810                let bytes_after_first_selection =
14811                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14812                let query_matches = query
14813                    .stream_find_iter(bytes_before_last_selection)
14814                    .map(|result| (last_selection.start, result))
14815                    .chain(
14816                        query
14817                            .stream_find_iter(bytes_after_first_selection)
14818                            .map(|result| (buffer.len(), result)),
14819                    );
14820                for (end_offset, query_match) in query_matches {
14821                    let query_match = query_match.unwrap(); // can only fail due to I/O
14822                    let offset_range =
14823                        end_offset - query_match.end()..end_offset - query_match.start();
14824
14825                    if !select_prev_state.wordwise
14826                        || (!buffer.is_inside_word(offset_range.start, None)
14827                            && !buffer.is_inside_word(offset_range.end, None))
14828                    {
14829                        next_selected_range = Some(offset_range);
14830                        break;
14831                    }
14832                }
14833
14834                if let Some(next_selected_range) = next_selected_range {
14835                    self.select_match_ranges(
14836                        next_selected_range,
14837                        last_selection.reversed,
14838                        action.replace_newest,
14839                        Some(Autoscroll::newest()),
14840                        window,
14841                        cx,
14842                    );
14843                } else {
14844                    select_prev_state.done = true;
14845                }
14846            }
14847
14848            self.select_prev_state = Some(select_prev_state);
14849        } else {
14850            let mut only_carets = true;
14851            let mut same_text_selected = true;
14852            let mut selected_text = None;
14853
14854            let mut selections_iter = selections.iter().peekable();
14855            while let Some(selection) = selections_iter.next() {
14856                if selection.start != selection.end {
14857                    only_carets = false;
14858                }
14859
14860                if same_text_selected {
14861                    if selected_text.is_none() {
14862                        selected_text =
14863                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14864                    }
14865
14866                    if let Some(next_selection) = selections_iter.peek() {
14867                        if next_selection.range().len() == selection.range().len() {
14868                            let next_selected_text = buffer
14869                                .text_for_range(next_selection.range())
14870                                .collect::<String>();
14871                            if Some(next_selected_text) != selected_text {
14872                                same_text_selected = false;
14873                                selected_text = None;
14874                            }
14875                        } else {
14876                            same_text_selected = false;
14877                            selected_text = None;
14878                        }
14879                    }
14880                }
14881            }
14882
14883            if only_carets {
14884                for selection in &mut selections {
14885                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14886                    selection.start = word_range.start;
14887                    selection.end = word_range.end;
14888                    selection.goal = SelectionGoal::None;
14889                    selection.reversed = false;
14890                    self.select_match_ranges(
14891                        selection.start..selection.end,
14892                        selection.reversed,
14893                        action.replace_newest,
14894                        Some(Autoscroll::newest()),
14895                        window,
14896                        cx,
14897                    );
14898                }
14899                if selections.len() == 1 {
14900                    let selection = selections
14901                        .last()
14902                        .expect("ensured that there's only one selection");
14903                    let query = buffer
14904                        .text_for_range(selection.start..selection.end)
14905                        .collect::<String>();
14906                    let is_empty = query.is_empty();
14907                    let select_state = SelectNextState {
14908                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
14909                        wordwise: true,
14910                        done: is_empty,
14911                    };
14912                    self.select_prev_state = Some(select_state);
14913                } else {
14914                    self.select_prev_state = None;
14915                }
14916            } else if let Some(selected_text) = selected_text {
14917                self.select_prev_state = Some(SelectNextState {
14918                    query: self
14919                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
14920                    wordwise: false,
14921                    done: false,
14922                });
14923                self.select_previous(action, window, cx)?;
14924            }
14925        }
14926        Ok(())
14927    }
14928
14929    /// Builds an `AhoCorasick` automaton from the provided patterns, while
14930    /// setting the case sensitivity based on the global
14931    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
14932    /// editor's settings.
14933    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
14934    where
14935        I: IntoIterator<Item = P>,
14936        P: AsRef<[u8]>,
14937    {
14938        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
14939            || EditorSettings::get_global(cx).search.case_sensitive,
14940            |value| value,
14941        );
14942
14943        let mut builder = AhoCorasickBuilder::new();
14944        builder.ascii_case_insensitive(!case_sensitive);
14945        builder.build(patterns)
14946    }
14947
14948    pub fn find_next_match(
14949        &mut self,
14950        _: &FindNextMatch,
14951        window: &mut Window,
14952        cx: &mut Context<Self>,
14953    ) -> Result<()> {
14954        let selections = self.selections.disjoint_anchors_arc();
14955        match selections.first() {
14956            Some(first) if selections.len() >= 2 => {
14957                self.change_selections(Default::default(), window, cx, |s| {
14958                    s.select_ranges([first.range()]);
14959                });
14960            }
14961            _ => self.select_next(
14962                &SelectNext {
14963                    replace_newest: true,
14964                },
14965                window,
14966                cx,
14967            )?,
14968        }
14969        Ok(())
14970    }
14971
14972    pub fn find_previous_match(
14973        &mut self,
14974        _: &FindPreviousMatch,
14975        window: &mut Window,
14976        cx: &mut Context<Self>,
14977    ) -> Result<()> {
14978        let selections = self.selections.disjoint_anchors_arc();
14979        match selections.last() {
14980            Some(last) if selections.len() >= 2 => {
14981                self.change_selections(Default::default(), window, cx, |s| {
14982                    s.select_ranges([last.range()]);
14983                });
14984            }
14985            _ => self.select_previous(
14986                &SelectPrevious {
14987                    replace_newest: true,
14988                },
14989                window,
14990                cx,
14991            )?,
14992        }
14993        Ok(())
14994    }
14995
14996    pub fn toggle_comments(
14997        &mut self,
14998        action: &ToggleComments,
14999        window: &mut Window,
15000        cx: &mut Context<Self>,
15001    ) {
15002        if self.read_only(cx) {
15003            return;
15004        }
15005        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15006        let text_layout_details = &self.text_layout_details(window);
15007        self.transact(window, cx, |this, window, cx| {
15008            let mut selections = this
15009                .selections
15010                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15011            let mut edits = Vec::new();
15012            let mut selection_edit_ranges = Vec::new();
15013            let mut last_toggled_row = None;
15014            let snapshot = this.buffer.read(cx).read(cx);
15015            let empty_str: Arc<str> = Arc::default();
15016            let mut suffixes_inserted = Vec::new();
15017            let ignore_indent = action.ignore_indent;
15018
15019            fn comment_prefix_range(
15020                snapshot: &MultiBufferSnapshot,
15021                row: MultiBufferRow,
15022                comment_prefix: &str,
15023                comment_prefix_whitespace: &str,
15024                ignore_indent: bool,
15025            ) -> Range<Point> {
15026                let indent_size = if ignore_indent {
15027                    0
15028                } else {
15029                    snapshot.indent_size_for_line(row).len
15030                };
15031
15032                let start = Point::new(row.0, indent_size);
15033
15034                let mut line_bytes = snapshot
15035                    .bytes_in_range(start..snapshot.max_point())
15036                    .flatten()
15037                    .copied();
15038
15039                // If this line currently begins with the line comment prefix, then record
15040                // the range containing the prefix.
15041                if line_bytes
15042                    .by_ref()
15043                    .take(comment_prefix.len())
15044                    .eq(comment_prefix.bytes())
15045                {
15046                    // Include any whitespace that matches the comment prefix.
15047                    let matching_whitespace_len = line_bytes
15048                        .zip(comment_prefix_whitespace.bytes())
15049                        .take_while(|(a, b)| a == b)
15050                        .count() as u32;
15051                    let end = Point::new(
15052                        start.row,
15053                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15054                    );
15055                    start..end
15056                } else {
15057                    start..start
15058                }
15059            }
15060
15061            fn comment_suffix_range(
15062                snapshot: &MultiBufferSnapshot,
15063                row: MultiBufferRow,
15064                comment_suffix: &str,
15065                comment_suffix_has_leading_space: bool,
15066            ) -> Range<Point> {
15067                let end = Point::new(row.0, snapshot.line_len(row));
15068                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15069
15070                let mut line_end_bytes = snapshot
15071                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15072                    .flatten()
15073                    .copied();
15074
15075                let leading_space_len = if suffix_start_column > 0
15076                    && line_end_bytes.next() == Some(b' ')
15077                    && comment_suffix_has_leading_space
15078                {
15079                    1
15080                } else {
15081                    0
15082                };
15083
15084                // If this line currently begins with the line comment prefix, then record
15085                // the range containing the prefix.
15086                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15087                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15088                    start..end
15089                } else {
15090                    end..end
15091                }
15092            }
15093
15094            // TODO: Handle selections that cross excerpts
15095            for selection in &mut selections {
15096                let start_column = snapshot
15097                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15098                    .len;
15099                let language = if let Some(language) =
15100                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15101                {
15102                    language
15103                } else {
15104                    continue;
15105                };
15106
15107                selection_edit_ranges.clear();
15108
15109                // If multiple selections contain a given row, avoid processing that
15110                // row more than once.
15111                let mut start_row = MultiBufferRow(selection.start.row);
15112                if last_toggled_row == Some(start_row) {
15113                    start_row = start_row.next_row();
15114                }
15115                let end_row =
15116                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15117                        MultiBufferRow(selection.end.row - 1)
15118                    } else {
15119                        MultiBufferRow(selection.end.row)
15120                    };
15121                last_toggled_row = Some(end_row);
15122
15123                if start_row > end_row {
15124                    continue;
15125                }
15126
15127                // If the language has line comments, toggle those.
15128                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15129
15130                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15131                if ignore_indent {
15132                    full_comment_prefixes = full_comment_prefixes
15133                        .into_iter()
15134                        .map(|s| Arc::from(s.trim_end()))
15135                        .collect();
15136                }
15137
15138                if !full_comment_prefixes.is_empty() {
15139                    let first_prefix = full_comment_prefixes
15140                        .first()
15141                        .expect("prefixes is non-empty");
15142                    let prefix_trimmed_lengths = full_comment_prefixes
15143                        .iter()
15144                        .map(|p| p.trim_end_matches(' ').len())
15145                        .collect::<SmallVec<[usize; 4]>>();
15146
15147                    let mut all_selection_lines_are_comments = true;
15148
15149                    for row in start_row.0..=end_row.0 {
15150                        let row = MultiBufferRow(row);
15151                        if start_row < end_row && snapshot.is_line_blank(row) {
15152                            continue;
15153                        }
15154
15155                        let prefix_range = full_comment_prefixes
15156                            .iter()
15157                            .zip(prefix_trimmed_lengths.iter().copied())
15158                            .map(|(prefix, trimmed_prefix_len)| {
15159                                comment_prefix_range(
15160                                    snapshot.deref(),
15161                                    row,
15162                                    &prefix[..trimmed_prefix_len],
15163                                    &prefix[trimmed_prefix_len..],
15164                                    ignore_indent,
15165                                )
15166                            })
15167                            .max_by_key(|range| range.end.column - range.start.column)
15168                            .expect("prefixes is non-empty");
15169
15170                        if prefix_range.is_empty() {
15171                            all_selection_lines_are_comments = false;
15172                        }
15173
15174                        selection_edit_ranges.push(prefix_range);
15175                    }
15176
15177                    if all_selection_lines_are_comments {
15178                        edits.extend(
15179                            selection_edit_ranges
15180                                .iter()
15181                                .cloned()
15182                                .map(|range| (range, empty_str.clone())),
15183                        );
15184                    } else {
15185                        let min_column = selection_edit_ranges
15186                            .iter()
15187                            .map(|range| range.start.column)
15188                            .min()
15189                            .unwrap_or(0);
15190                        edits.extend(selection_edit_ranges.iter().map(|range| {
15191                            let position = Point::new(range.start.row, min_column);
15192                            (position..position, first_prefix.clone())
15193                        }));
15194                    }
15195                } else if let Some(BlockCommentConfig {
15196                    start: full_comment_prefix,
15197                    end: comment_suffix,
15198                    ..
15199                }) = language.block_comment()
15200                {
15201                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15202                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15203                    let prefix_range = comment_prefix_range(
15204                        snapshot.deref(),
15205                        start_row,
15206                        comment_prefix,
15207                        comment_prefix_whitespace,
15208                        ignore_indent,
15209                    );
15210                    let suffix_range = comment_suffix_range(
15211                        snapshot.deref(),
15212                        end_row,
15213                        comment_suffix.trim_start_matches(' '),
15214                        comment_suffix.starts_with(' '),
15215                    );
15216
15217                    if prefix_range.is_empty() || suffix_range.is_empty() {
15218                        edits.push((
15219                            prefix_range.start..prefix_range.start,
15220                            full_comment_prefix.clone(),
15221                        ));
15222                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15223                        suffixes_inserted.push((end_row, comment_suffix.len()));
15224                    } else {
15225                        edits.push((prefix_range, empty_str.clone()));
15226                        edits.push((suffix_range, empty_str.clone()));
15227                    }
15228                } else {
15229                    continue;
15230                }
15231            }
15232
15233            drop(snapshot);
15234            this.buffer.update(cx, |buffer, cx| {
15235                buffer.edit(edits, None, cx);
15236            });
15237
15238            // Adjust selections so that they end before any comment suffixes that
15239            // were inserted.
15240            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15241            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15242            let snapshot = this.buffer.read(cx).read(cx);
15243            for selection in &mut selections {
15244                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15245                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15246                        Ordering::Less => {
15247                            suffixes_inserted.next();
15248                            continue;
15249                        }
15250                        Ordering::Greater => break,
15251                        Ordering::Equal => {
15252                            if selection.end.column == snapshot.line_len(row) {
15253                                if selection.is_empty() {
15254                                    selection.start.column -= suffix_len as u32;
15255                                }
15256                                selection.end.column -= suffix_len as u32;
15257                            }
15258                            break;
15259                        }
15260                    }
15261                }
15262            }
15263
15264            drop(snapshot);
15265            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15266
15267            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15268            let selections_on_single_row = selections.windows(2).all(|selections| {
15269                selections[0].start.row == selections[1].start.row
15270                    && selections[0].end.row == selections[1].end.row
15271                    && selections[0].start.row == selections[0].end.row
15272            });
15273            let selections_selecting = selections
15274                .iter()
15275                .any(|selection| selection.start != selection.end);
15276            let advance_downwards = action.advance_downwards
15277                && selections_on_single_row
15278                && !selections_selecting
15279                && !matches!(this.mode, EditorMode::SingleLine);
15280
15281            if advance_downwards {
15282                let snapshot = this.buffer.read(cx).snapshot(cx);
15283
15284                this.change_selections(Default::default(), window, cx, |s| {
15285                    s.move_cursors_with(|display_snapshot, display_point, _| {
15286                        let mut point = display_point.to_point(display_snapshot);
15287                        point.row += 1;
15288                        point = snapshot.clip_point(point, Bias::Left);
15289                        let display_point = point.to_display_point(display_snapshot);
15290                        let goal = SelectionGoal::HorizontalPosition(
15291                            display_snapshot
15292                                .x_for_display_point(display_point, text_layout_details)
15293                                .into(),
15294                        );
15295                        (display_point, goal)
15296                    })
15297                });
15298            }
15299        });
15300    }
15301
15302    pub fn select_enclosing_symbol(
15303        &mut self,
15304        _: &SelectEnclosingSymbol,
15305        window: &mut Window,
15306        cx: &mut Context<Self>,
15307    ) {
15308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15309
15310        let buffer = self.buffer.read(cx).snapshot(cx);
15311        let old_selections = self
15312            .selections
15313            .all::<usize>(&self.display_snapshot(cx))
15314            .into_boxed_slice();
15315
15316        fn update_selection(
15317            selection: &Selection<usize>,
15318            buffer_snap: &MultiBufferSnapshot,
15319        ) -> Option<Selection<usize>> {
15320            let cursor = selection.head();
15321            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15322            for symbol in symbols.iter().rev() {
15323                let start = symbol.range.start.to_offset(buffer_snap);
15324                let end = symbol.range.end.to_offset(buffer_snap);
15325                let new_range = start..end;
15326                if start < selection.start || end > selection.end {
15327                    return Some(Selection {
15328                        id: selection.id,
15329                        start: new_range.start,
15330                        end: new_range.end,
15331                        goal: SelectionGoal::None,
15332                        reversed: selection.reversed,
15333                    });
15334                }
15335            }
15336            None
15337        }
15338
15339        let mut selected_larger_symbol = false;
15340        let new_selections = old_selections
15341            .iter()
15342            .map(|selection| match update_selection(selection, &buffer) {
15343                Some(new_selection) => {
15344                    if new_selection.range() != selection.range() {
15345                        selected_larger_symbol = true;
15346                    }
15347                    new_selection
15348                }
15349                None => selection.clone(),
15350            })
15351            .collect::<Vec<_>>();
15352
15353        if selected_larger_symbol {
15354            self.change_selections(Default::default(), window, cx, |s| {
15355                s.select(new_selections);
15356            });
15357        }
15358    }
15359
15360    pub fn select_larger_syntax_node(
15361        &mut self,
15362        _: &SelectLargerSyntaxNode,
15363        window: &mut Window,
15364        cx: &mut Context<Self>,
15365    ) {
15366        let Some(visible_row_count) = self.visible_row_count() else {
15367            return;
15368        };
15369        let old_selections: Box<[_]> = self
15370            .selections
15371            .all::<usize>(&self.display_snapshot(cx))
15372            .into();
15373        if old_selections.is_empty() {
15374            return;
15375        }
15376
15377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15378
15379        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15380        let buffer = self.buffer.read(cx).snapshot(cx);
15381
15382        let mut selected_larger_node = false;
15383        let mut new_selections = old_selections
15384            .iter()
15385            .map(|selection| {
15386                let old_range = selection.start..selection.end;
15387
15388                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15389                    // manually select word at selection
15390                    if ["string_content", "inline"].contains(&node.kind()) {
15391                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15392                        // ignore if word is already selected
15393                        if !word_range.is_empty() && old_range != word_range {
15394                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15395                            // only select word if start and end point belongs to same word
15396                            if word_range == last_word_range {
15397                                selected_larger_node = true;
15398                                return Selection {
15399                                    id: selection.id,
15400                                    start: word_range.start,
15401                                    end: word_range.end,
15402                                    goal: SelectionGoal::None,
15403                                    reversed: selection.reversed,
15404                                };
15405                            }
15406                        }
15407                    }
15408                }
15409
15410                let mut new_range = old_range.clone();
15411                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15412                    new_range = range;
15413                    if !node.is_named() {
15414                        continue;
15415                    }
15416                    if !display_map.intersects_fold(new_range.start)
15417                        && !display_map.intersects_fold(new_range.end)
15418                    {
15419                        break;
15420                    }
15421                }
15422
15423                selected_larger_node |= new_range != old_range;
15424                Selection {
15425                    id: selection.id,
15426                    start: new_range.start,
15427                    end: new_range.end,
15428                    goal: SelectionGoal::None,
15429                    reversed: selection.reversed,
15430                }
15431            })
15432            .collect::<Vec<_>>();
15433
15434        if !selected_larger_node {
15435            return; // don't put this call in the history
15436        }
15437
15438        // scroll based on transformation done to the last selection created by the user
15439        let (last_old, last_new) = old_selections
15440            .last()
15441            .zip(new_selections.last().cloned())
15442            .expect("old_selections isn't empty");
15443
15444        // revert selection
15445        let is_selection_reversed = {
15446            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15447            new_selections.last_mut().expect("checked above").reversed =
15448                should_newest_selection_be_reversed;
15449            should_newest_selection_be_reversed
15450        };
15451
15452        if selected_larger_node {
15453            self.select_syntax_node_history.disable_clearing = true;
15454            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15455                s.select(new_selections.clone());
15456            });
15457            self.select_syntax_node_history.disable_clearing = false;
15458        }
15459
15460        let start_row = last_new.start.to_display_point(&display_map).row().0;
15461        let end_row = last_new.end.to_display_point(&display_map).row().0;
15462        let selection_height = end_row - start_row + 1;
15463        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15464
15465        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15466        let scroll_behavior = if fits_on_the_screen {
15467            self.request_autoscroll(Autoscroll::fit(), cx);
15468            SelectSyntaxNodeScrollBehavior::FitSelection
15469        } else if is_selection_reversed {
15470            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15471            SelectSyntaxNodeScrollBehavior::CursorTop
15472        } else {
15473            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15474            SelectSyntaxNodeScrollBehavior::CursorBottom
15475        };
15476
15477        self.select_syntax_node_history.push((
15478            old_selections,
15479            scroll_behavior,
15480            is_selection_reversed,
15481        ));
15482    }
15483
15484    pub fn select_smaller_syntax_node(
15485        &mut self,
15486        _: &SelectSmallerSyntaxNode,
15487        window: &mut Window,
15488        cx: &mut Context<Self>,
15489    ) {
15490        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15491
15492        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15493            self.select_syntax_node_history.pop()
15494        {
15495            if let Some(selection) = selections.last_mut() {
15496                selection.reversed = is_selection_reversed;
15497            }
15498
15499            self.select_syntax_node_history.disable_clearing = true;
15500            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15501                s.select(selections.to_vec());
15502            });
15503            self.select_syntax_node_history.disable_clearing = false;
15504
15505            match scroll_behavior {
15506                SelectSyntaxNodeScrollBehavior::CursorTop => {
15507                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15508                }
15509                SelectSyntaxNodeScrollBehavior::FitSelection => {
15510                    self.request_autoscroll(Autoscroll::fit(), cx);
15511                }
15512                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15513                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15514                }
15515            }
15516        }
15517    }
15518
15519    pub fn unwrap_syntax_node(
15520        &mut self,
15521        _: &UnwrapSyntaxNode,
15522        window: &mut Window,
15523        cx: &mut Context<Self>,
15524    ) {
15525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15526
15527        let buffer = self.buffer.read(cx).snapshot(cx);
15528        let selections = self
15529            .selections
15530            .all::<usize>(&self.display_snapshot(cx))
15531            .into_iter()
15532            // subtracting the offset requires sorting
15533            .sorted_by_key(|i| i.start);
15534
15535        let full_edits = selections
15536            .into_iter()
15537            .filter_map(|selection| {
15538                let child = if selection.is_empty()
15539                    && let Some((_, ancestor_range)) =
15540                        buffer.syntax_ancestor(selection.start..selection.end)
15541                {
15542                    ancestor_range
15543                } else {
15544                    selection.range()
15545                };
15546
15547                let mut parent = child.clone();
15548                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15549                    parent = ancestor_range;
15550                    if parent.start < child.start || parent.end > child.end {
15551                        break;
15552                    }
15553                }
15554
15555                if parent == child {
15556                    return None;
15557                }
15558                let text = buffer.text_for_range(child).collect::<String>();
15559                Some((selection.id, parent, text))
15560            })
15561            .collect::<Vec<_>>();
15562        if full_edits.is_empty() {
15563            return;
15564        }
15565
15566        self.transact(window, cx, |this, window, cx| {
15567            this.buffer.update(cx, |buffer, cx| {
15568                buffer.edit(
15569                    full_edits
15570                        .iter()
15571                        .map(|(_, p, t)| (p.clone(), t.clone()))
15572                        .collect::<Vec<_>>(),
15573                    None,
15574                    cx,
15575                );
15576            });
15577            this.change_selections(Default::default(), window, cx, |s| {
15578                let mut offset = 0;
15579                let mut selections = vec![];
15580                for (id, parent, text) in full_edits {
15581                    let start = parent.start - offset;
15582                    offset += parent.len() - text.len();
15583                    selections.push(Selection {
15584                        id,
15585                        start,
15586                        end: start + text.len(),
15587                        reversed: false,
15588                        goal: Default::default(),
15589                    });
15590                }
15591                s.select(selections);
15592            });
15593        });
15594    }
15595
15596    pub fn select_next_syntax_node(
15597        &mut self,
15598        _: &SelectNextSyntaxNode,
15599        window: &mut Window,
15600        cx: &mut Context<Self>,
15601    ) {
15602        let old_selections: Box<[_]> = self
15603            .selections
15604            .all::<usize>(&self.display_snapshot(cx))
15605            .into();
15606        if old_selections.is_empty() {
15607            return;
15608        }
15609
15610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15611
15612        let buffer = self.buffer.read(cx).snapshot(cx);
15613        let mut selected_sibling = false;
15614
15615        let new_selections = old_selections
15616            .iter()
15617            .map(|selection| {
15618                let old_range = selection.start..selection.end;
15619
15620                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15621                    let new_range = node.byte_range();
15622                    selected_sibling = true;
15623                    Selection {
15624                        id: selection.id,
15625                        start: new_range.start,
15626                        end: new_range.end,
15627                        goal: SelectionGoal::None,
15628                        reversed: selection.reversed,
15629                    }
15630                } else {
15631                    selection.clone()
15632                }
15633            })
15634            .collect::<Vec<_>>();
15635
15636        if selected_sibling {
15637            self.change_selections(
15638                SelectionEffects::scroll(Autoscroll::fit()),
15639                window,
15640                cx,
15641                |s| {
15642                    s.select(new_selections);
15643                },
15644            );
15645        }
15646    }
15647
15648    pub fn select_prev_syntax_node(
15649        &mut self,
15650        _: &SelectPreviousSyntaxNode,
15651        window: &mut Window,
15652        cx: &mut Context<Self>,
15653    ) {
15654        let old_selections: Box<[_]> = self
15655            .selections
15656            .all::<usize>(&self.display_snapshot(cx))
15657            .into();
15658        if old_selections.is_empty() {
15659            return;
15660        }
15661
15662        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15663
15664        let buffer = self.buffer.read(cx).snapshot(cx);
15665        let mut selected_sibling = false;
15666
15667        let new_selections = old_selections
15668            .iter()
15669            .map(|selection| {
15670                let old_range = selection.start..selection.end;
15671
15672                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15673                    let new_range = node.byte_range();
15674                    selected_sibling = true;
15675                    Selection {
15676                        id: selection.id,
15677                        start: new_range.start,
15678                        end: new_range.end,
15679                        goal: SelectionGoal::None,
15680                        reversed: selection.reversed,
15681                    }
15682                } else {
15683                    selection.clone()
15684                }
15685            })
15686            .collect::<Vec<_>>();
15687
15688        if selected_sibling {
15689            self.change_selections(
15690                SelectionEffects::scroll(Autoscroll::fit()),
15691                window,
15692                cx,
15693                |s| {
15694                    s.select(new_selections);
15695                },
15696            );
15697        }
15698    }
15699
15700    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15701        if !EditorSettings::get_global(cx).gutter.runnables {
15702            self.clear_tasks();
15703            return Task::ready(());
15704        }
15705        let project = self.project().map(Entity::downgrade);
15706        let task_sources = self.lsp_task_sources(cx);
15707        let multi_buffer = self.buffer.downgrade();
15708        cx.spawn_in(window, async move |editor, cx| {
15709            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15710            let Some(project) = project.and_then(|p| p.upgrade()) else {
15711                return;
15712            };
15713            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15714                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15715            }) else {
15716                return;
15717            };
15718
15719            let hide_runnables = project
15720                .update(cx, |project, _| project.is_via_collab())
15721                .unwrap_or(true);
15722            if hide_runnables {
15723                return;
15724            }
15725            let new_rows =
15726                cx.background_spawn({
15727                    let snapshot = display_snapshot.clone();
15728                    async move {
15729                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15730                    }
15731                })
15732                    .await;
15733            let Ok(lsp_tasks) =
15734                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15735            else {
15736                return;
15737            };
15738            let lsp_tasks = lsp_tasks.await;
15739
15740            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15741                lsp_tasks
15742                    .into_iter()
15743                    .flat_map(|(kind, tasks)| {
15744                        tasks.into_iter().filter_map(move |(location, task)| {
15745                            Some((kind.clone(), location?, task))
15746                        })
15747                    })
15748                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15749                        let buffer = location.target.buffer;
15750                        let buffer_snapshot = buffer.read(cx).snapshot();
15751                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15752                            |(excerpt_id, snapshot, _)| {
15753                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15754                                    display_snapshot
15755                                        .buffer_snapshot()
15756                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15757                                } else {
15758                                    None
15759                                }
15760                            },
15761                        );
15762                        if let Some(offset) = offset {
15763                            let task_buffer_range =
15764                                location.target.range.to_point(&buffer_snapshot);
15765                            let context_buffer_range =
15766                                task_buffer_range.to_offset(&buffer_snapshot);
15767                            let context_range = BufferOffset(context_buffer_range.start)
15768                                ..BufferOffset(context_buffer_range.end);
15769
15770                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15771                                .or_insert_with(|| RunnableTasks {
15772                                    templates: Vec::new(),
15773                                    offset,
15774                                    column: task_buffer_range.start.column,
15775                                    extra_variables: HashMap::default(),
15776                                    context_range,
15777                                })
15778                                .templates
15779                                .push((kind, task.original_task().clone()));
15780                        }
15781
15782                        acc
15783                    })
15784            }) else {
15785                return;
15786            };
15787
15788            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15789                buffer.language_settings(cx).tasks.prefer_lsp
15790            }) else {
15791                return;
15792            };
15793
15794            let rows = Self::runnable_rows(
15795                project,
15796                display_snapshot,
15797                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15798                new_rows,
15799                cx.clone(),
15800            )
15801            .await;
15802            editor
15803                .update(cx, |editor, _| {
15804                    editor.clear_tasks();
15805                    for (key, mut value) in rows {
15806                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15807                            value.templates.extend(lsp_tasks.templates);
15808                        }
15809
15810                        editor.insert_tasks(key, value);
15811                    }
15812                    for (key, value) in lsp_tasks_by_rows {
15813                        editor.insert_tasks(key, value);
15814                    }
15815                })
15816                .ok();
15817        })
15818    }
15819    fn fetch_runnable_ranges(
15820        snapshot: &DisplaySnapshot,
15821        range: Range<Anchor>,
15822    ) -> Vec<language::RunnableRange> {
15823        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15824    }
15825
15826    fn runnable_rows(
15827        project: Entity<Project>,
15828        snapshot: DisplaySnapshot,
15829        prefer_lsp: bool,
15830        runnable_ranges: Vec<RunnableRange>,
15831        cx: AsyncWindowContext,
15832    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15833        cx.spawn(async move |cx| {
15834            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15835            for mut runnable in runnable_ranges {
15836                let Some(tasks) = cx
15837                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15838                    .ok()
15839                else {
15840                    continue;
15841                };
15842                let mut tasks = tasks.await;
15843
15844                if prefer_lsp {
15845                    tasks.retain(|(task_kind, _)| {
15846                        !matches!(task_kind, TaskSourceKind::Language { .. })
15847                    });
15848                }
15849                if tasks.is_empty() {
15850                    continue;
15851                }
15852
15853                let point = runnable
15854                    .run_range
15855                    .start
15856                    .to_point(&snapshot.buffer_snapshot());
15857                let Some(row) = snapshot
15858                    .buffer_snapshot()
15859                    .buffer_line_for_row(MultiBufferRow(point.row))
15860                    .map(|(_, range)| range.start.row)
15861                else {
15862                    continue;
15863                };
15864
15865                let context_range =
15866                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15867                runnable_rows.push((
15868                    (runnable.buffer_id, row),
15869                    RunnableTasks {
15870                        templates: tasks,
15871                        offset: snapshot
15872                            .buffer_snapshot()
15873                            .anchor_before(runnable.run_range.start),
15874                        context_range,
15875                        column: point.column,
15876                        extra_variables: runnable.extra_captures,
15877                    },
15878                ));
15879            }
15880            runnable_rows
15881        })
15882    }
15883
15884    fn templates_with_tags(
15885        project: &Entity<Project>,
15886        runnable: &mut Runnable,
15887        cx: &mut App,
15888    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15889        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15890            let (worktree_id, file) = project
15891                .buffer_for_id(runnable.buffer, cx)
15892                .and_then(|buffer| buffer.read(cx).file())
15893                .map(|file| (file.worktree_id(cx), file.clone()))
15894                .unzip();
15895
15896            (
15897                project.task_store().read(cx).task_inventory().cloned(),
15898                worktree_id,
15899                file,
15900            )
15901        });
15902
15903        let tags = mem::take(&mut runnable.tags);
15904        let language = runnable.language.clone();
15905        cx.spawn(async move |cx| {
15906            let mut templates_with_tags = Vec::new();
15907            if let Some(inventory) = inventory {
15908                for RunnableTag(tag) in tags {
15909                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15910                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15911                    }) else {
15912                        return templates_with_tags;
15913                    };
15914                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15915                        move |(_, template)| {
15916                            template.tags.iter().any(|source_tag| source_tag == &tag)
15917                        },
15918                    ));
15919                }
15920            }
15921            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15922
15923            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15924                // Strongest source wins; if we have worktree tag binding, prefer that to
15925                // global and language bindings;
15926                // if we have a global binding, prefer that to language binding.
15927                let first_mismatch = templates_with_tags
15928                    .iter()
15929                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15930                if let Some(index) = first_mismatch {
15931                    templates_with_tags.truncate(index);
15932                }
15933            }
15934
15935            templates_with_tags
15936        })
15937    }
15938
15939    pub fn move_to_enclosing_bracket(
15940        &mut self,
15941        _: &MoveToEnclosingBracket,
15942        window: &mut Window,
15943        cx: &mut Context<Self>,
15944    ) {
15945        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15946        self.change_selections(Default::default(), window, cx, |s| {
15947            s.move_offsets_with(|snapshot, selection| {
15948                let Some(enclosing_bracket_ranges) =
15949                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15950                else {
15951                    return;
15952                };
15953
15954                let mut best_length = usize::MAX;
15955                let mut best_inside = false;
15956                let mut best_in_bracket_range = false;
15957                let mut best_destination = None;
15958                for (open, close) in enclosing_bracket_ranges {
15959                    let close = close.to_inclusive();
15960                    let length = close.end() - open.start;
15961                    let inside = selection.start >= open.end && selection.end <= *close.start();
15962                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15963                        || close.contains(&selection.head());
15964
15965                    // If best is next to a bracket and current isn't, skip
15966                    if !in_bracket_range && best_in_bracket_range {
15967                        continue;
15968                    }
15969
15970                    // Prefer smaller lengths unless best is inside and current isn't
15971                    if length > best_length && (best_inside || !inside) {
15972                        continue;
15973                    }
15974
15975                    best_length = length;
15976                    best_inside = inside;
15977                    best_in_bracket_range = in_bracket_range;
15978                    best_destination = Some(
15979                        if close.contains(&selection.start) && close.contains(&selection.end) {
15980                            if inside { open.end } else { open.start }
15981                        } else if inside {
15982                            *close.start()
15983                        } else {
15984                            *close.end()
15985                        },
15986                    );
15987                }
15988
15989                if let Some(destination) = best_destination {
15990                    selection.collapse_to(destination, SelectionGoal::None);
15991                }
15992            })
15993        });
15994    }
15995
15996    pub fn undo_selection(
15997        &mut self,
15998        _: &UndoSelection,
15999        window: &mut Window,
16000        cx: &mut Context<Self>,
16001    ) {
16002        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16003        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16004            self.selection_history.mode = SelectionHistoryMode::Undoing;
16005            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16006                this.end_selection(window, cx);
16007                this.change_selections(
16008                    SelectionEffects::scroll(Autoscroll::newest()),
16009                    window,
16010                    cx,
16011                    |s| s.select_anchors(entry.selections.to_vec()),
16012                );
16013            });
16014            self.selection_history.mode = SelectionHistoryMode::Normal;
16015
16016            self.select_next_state = entry.select_next_state;
16017            self.select_prev_state = entry.select_prev_state;
16018            self.add_selections_state = entry.add_selections_state;
16019        }
16020    }
16021
16022    pub fn redo_selection(
16023        &mut self,
16024        _: &RedoSelection,
16025        window: &mut Window,
16026        cx: &mut Context<Self>,
16027    ) {
16028        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16029        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16030            self.selection_history.mode = SelectionHistoryMode::Redoing;
16031            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16032                this.end_selection(window, cx);
16033                this.change_selections(
16034                    SelectionEffects::scroll(Autoscroll::newest()),
16035                    window,
16036                    cx,
16037                    |s| s.select_anchors(entry.selections.to_vec()),
16038                );
16039            });
16040            self.selection_history.mode = SelectionHistoryMode::Normal;
16041
16042            self.select_next_state = entry.select_next_state;
16043            self.select_prev_state = entry.select_prev_state;
16044            self.add_selections_state = entry.add_selections_state;
16045        }
16046    }
16047
16048    pub fn expand_excerpts(
16049        &mut self,
16050        action: &ExpandExcerpts,
16051        _: &mut Window,
16052        cx: &mut Context<Self>,
16053    ) {
16054        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16055    }
16056
16057    pub fn expand_excerpts_down(
16058        &mut self,
16059        action: &ExpandExcerptsDown,
16060        _: &mut Window,
16061        cx: &mut Context<Self>,
16062    ) {
16063        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16064    }
16065
16066    pub fn expand_excerpts_up(
16067        &mut self,
16068        action: &ExpandExcerptsUp,
16069        _: &mut Window,
16070        cx: &mut Context<Self>,
16071    ) {
16072        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16073    }
16074
16075    pub fn expand_excerpts_for_direction(
16076        &mut self,
16077        lines: u32,
16078        direction: ExpandExcerptDirection,
16079
16080        cx: &mut Context<Self>,
16081    ) {
16082        let selections = self.selections.disjoint_anchors_arc();
16083
16084        let lines = if lines == 0 {
16085            EditorSettings::get_global(cx).expand_excerpt_lines
16086        } else {
16087            lines
16088        };
16089
16090        self.buffer.update(cx, |buffer, cx| {
16091            let snapshot = buffer.snapshot(cx);
16092            let mut excerpt_ids = selections
16093                .iter()
16094                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16095                .collect::<Vec<_>>();
16096            excerpt_ids.sort();
16097            excerpt_ids.dedup();
16098            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16099        })
16100    }
16101
16102    pub fn expand_excerpt(
16103        &mut self,
16104        excerpt: ExcerptId,
16105        direction: ExpandExcerptDirection,
16106        window: &mut Window,
16107        cx: &mut Context<Self>,
16108    ) {
16109        let current_scroll_position = self.scroll_position(cx);
16110        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16111        let mut scroll = None;
16112
16113        if direction == ExpandExcerptDirection::Down {
16114            let multi_buffer = self.buffer.read(cx);
16115            let snapshot = multi_buffer.snapshot(cx);
16116            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16117                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16118                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16119            {
16120                let buffer_snapshot = buffer.read(cx).snapshot();
16121                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16122                let last_row = buffer_snapshot.max_point().row;
16123                let lines_below = last_row.saturating_sub(excerpt_end_row);
16124                if lines_below >= lines_to_expand {
16125                    scroll = Some(
16126                        current_scroll_position
16127                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16128                    );
16129                }
16130            }
16131        }
16132        if direction == ExpandExcerptDirection::Up
16133            && self
16134                .buffer
16135                .read(cx)
16136                .snapshot(cx)
16137                .excerpt_before(excerpt)
16138                .is_none()
16139        {
16140            scroll = Some(current_scroll_position);
16141        }
16142
16143        self.buffer.update(cx, |buffer, cx| {
16144            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16145        });
16146
16147        if let Some(new_scroll_position) = scroll {
16148            self.set_scroll_position(new_scroll_position, window, cx);
16149        }
16150    }
16151
16152    pub fn go_to_singleton_buffer_point(
16153        &mut self,
16154        point: Point,
16155        window: &mut Window,
16156        cx: &mut Context<Self>,
16157    ) {
16158        self.go_to_singleton_buffer_range(point..point, window, cx);
16159    }
16160
16161    pub fn go_to_singleton_buffer_range(
16162        &mut self,
16163        range: Range<Point>,
16164        window: &mut Window,
16165        cx: &mut Context<Self>,
16166    ) {
16167        let multibuffer = self.buffer().read(cx);
16168        let Some(buffer) = multibuffer.as_singleton() else {
16169            return;
16170        };
16171        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16172            return;
16173        };
16174        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16175            return;
16176        };
16177        self.change_selections(
16178            SelectionEffects::default().nav_history(true),
16179            window,
16180            cx,
16181            |s| s.select_anchor_ranges([start..end]),
16182        );
16183    }
16184
16185    pub fn go_to_diagnostic(
16186        &mut self,
16187        action: &GoToDiagnostic,
16188        window: &mut Window,
16189        cx: &mut Context<Self>,
16190    ) {
16191        if !self.diagnostics_enabled() {
16192            return;
16193        }
16194        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16195        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16196    }
16197
16198    pub fn go_to_prev_diagnostic(
16199        &mut self,
16200        action: &GoToPreviousDiagnostic,
16201        window: &mut Window,
16202        cx: &mut Context<Self>,
16203    ) {
16204        if !self.diagnostics_enabled() {
16205            return;
16206        }
16207        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16208        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16209    }
16210
16211    pub fn go_to_diagnostic_impl(
16212        &mut self,
16213        direction: Direction,
16214        severity: GoToDiagnosticSeverityFilter,
16215        window: &mut Window,
16216        cx: &mut Context<Self>,
16217    ) {
16218        let buffer = self.buffer.read(cx).snapshot(cx);
16219        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16220
16221        let mut active_group_id = None;
16222        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16223            && active_group.active_range.start.to_offset(&buffer) == selection.start
16224        {
16225            active_group_id = Some(active_group.group_id);
16226        }
16227
16228        fn filtered<'a>(
16229            severity: GoToDiagnosticSeverityFilter,
16230            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16231        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16232            diagnostics
16233                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16234                .filter(|entry| entry.range.start != entry.range.end)
16235                .filter(|entry| !entry.diagnostic.is_unnecessary)
16236        }
16237
16238        let before = filtered(
16239            severity,
16240            buffer
16241                .diagnostics_in_range(0..selection.start)
16242                .filter(|entry| entry.range.start <= selection.start),
16243        );
16244        let after = filtered(
16245            severity,
16246            buffer
16247                .diagnostics_in_range(selection.start..buffer.len())
16248                .filter(|entry| entry.range.start >= selection.start),
16249        );
16250
16251        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16252        if direction == Direction::Prev {
16253            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16254            {
16255                for diagnostic in prev_diagnostics.into_iter().rev() {
16256                    if diagnostic.range.start != selection.start
16257                        || active_group_id
16258                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16259                    {
16260                        found = Some(diagnostic);
16261                        break 'outer;
16262                    }
16263                }
16264            }
16265        } else {
16266            for diagnostic in after.chain(before) {
16267                if diagnostic.range.start != selection.start
16268                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16269                {
16270                    found = Some(diagnostic);
16271                    break;
16272                }
16273            }
16274        }
16275        let Some(next_diagnostic) = found else {
16276            return;
16277        };
16278
16279        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16280        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16281            return;
16282        };
16283        let snapshot = self.snapshot(window, cx);
16284        if snapshot.intersects_fold(next_diagnostic.range.start) {
16285            self.unfold_ranges(
16286                std::slice::from_ref(&next_diagnostic.range),
16287                true,
16288                false,
16289                cx,
16290            );
16291        }
16292        self.change_selections(Default::default(), window, cx, |s| {
16293            s.select_ranges(vec![
16294                next_diagnostic.range.start..next_diagnostic.range.start,
16295            ])
16296        });
16297        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16298        self.refresh_edit_prediction(false, true, window, cx);
16299    }
16300
16301    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16302        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16303        let snapshot = self.snapshot(window, cx);
16304        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16305        self.go_to_hunk_before_or_after_position(
16306            &snapshot,
16307            selection.head(),
16308            Direction::Next,
16309            window,
16310            cx,
16311        );
16312    }
16313
16314    pub fn go_to_hunk_before_or_after_position(
16315        &mut self,
16316        snapshot: &EditorSnapshot,
16317        position: Point,
16318        direction: Direction,
16319        window: &mut Window,
16320        cx: &mut Context<Editor>,
16321    ) {
16322        let row = if direction == Direction::Next {
16323            self.hunk_after_position(snapshot, position)
16324                .map(|hunk| hunk.row_range.start)
16325        } else {
16326            self.hunk_before_position(snapshot, position)
16327        };
16328
16329        if let Some(row) = row {
16330            let destination = Point::new(row.0, 0);
16331            let autoscroll = Autoscroll::center();
16332
16333            self.unfold_ranges(&[destination..destination], false, false, cx);
16334            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16335                s.select_ranges([destination..destination]);
16336            });
16337        }
16338    }
16339
16340    fn hunk_after_position(
16341        &mut self,
16342        snapshot: &EditorSnapshot,
16343        position: Point,
16344    ) -> Option<MultiBufferDiffHunk> {
16345        snapshot
16346            .buffer_snapshot()
16347            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16348            .find(|hunk| hunk.row_range.start.0 > position.row)
16349            .or_else(|| {
16350                snapshot
16351                    .buffer_snapshot()
16352                    .diff_hunks_in_range(Point::zero()..position)
16353                    .find(|hunk| hunk.row_range.end.0 < position.row)
16354            })
16355    }
16356
16357    fn go_to_prev_hunk(
16358        &mut self,
16359        _: &GoToPreviousHunk,
16360        window: &mut Window,
16361        cx: &mut Context<Self>,
16362    ) {
16363        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16364        let snapshot = self.snapshot(window, cx);
16365        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16366        self.go_to_hunk_before_or_after_position(
16367            &snapshot,
16368            selection.head(),
16369            Direction::Prev,
16370            window,
16371            cx,
16372        );
16373    }
16374
16375    fn hunk_before_position(
16376        &mut self,
16377        snapshot: &EditorSnapshot,
16378        position: Point,
16379    ) -> Option<MultiBufferRow> {
16380        snapshot
16381            .buffer_snapshot()
16382            .diff_hunk_before(position)
16383            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16384    }
16385
16386    fn go_to_next_change(
16387        &mut self,
16388        _: &GoToNextChange,
16389        window: &mut Window,
16390        cx: &mut Context<Self>,
16391    ) {
16392        if let Some(selections) = self
16393            .change_list
16394            .next_change(1, Direction::Next)
16395            .map(|s| s.to_vec())
16396        {
16397            self.change_selections(Default::default(), window, cx, |s| {
16398                let map = s.display_snapshot();
16399                s.select_display_ranges(selections.iter().map(|a| {
16400                    let point = a.to_display_point(&map);
16401                    point..point
16402                }))
16403            })
16404        }
16405    }
16406
16407    fn go_to_previous_change(
16408        &mut self,
16409        _: &GoToPreviousChange,
16410        window: &mut Window,
16411        cx: &mut Context<Self>,
16412    ) {
16413        if let Some(selections) = self
16414            .change_list
16415            .next_change(1, Direction::Prev)
16416            .map(|s| s.to_vec())
16417        {
16418            self.change_selections(Default::default(), window, cx, |s| {
16419                let map = s.display_snapshot();
16420                s.select_display_ranges(selections.iter().map(|a| {
16421                    let point = a.to_display_point(&map);
16422                    point..point
16423                }))
16424            })
16425        }
16426    }
16427
16428    pub fn go_to_next_document_highlight(
16429        &mut self,
16430        _: &GoToNextDocumentHighlight,
16431        window: &mut Window,
16432        cx: &mut Context<Self>,
16433    ) {
16434        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16435    }
16436
16437    pub fn go_to_prev_document_highlight(
16438        &mut self,
16439        _: &GoToPreviousDocumentHighlight,
16440        window: &mut Window,
16441        cx: &mut Context<Self>,
16442    ) {
16443        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16444    }
16445
16446    pub fn go_to_document_highlight_before_or_after_position(
16447        &mut self,
16448        direction: Direction,
16449        window: &mut Window,
16450        cx: &mut Context<Editor>,
16451    ) {
16452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16453        let snapshot = self.snapshot(window, cx);
16454        let buffer = &snapshot.buffer_snapshot();
16455        let position = self
16456            .selections
16457            .newest::<Point>(&snapshot.display_snapshot)
16458            .head();
16459        let anchor_position = buffer.anchor_after(position);
16460
16461        // Get all document highlights (both read and write)
16462        let mut all_highlights = Vec::new();
16463
16464        if let Some((_, read_highlights)) = self
16465            .background_highlights
16466            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16467        {
16468            all_highlights.extend(read_highlights.iter());
16469        }
16470
16471        if let Some((_, write_highlights)) = self
16472            .background_highlights
16473            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16474        {
16475            all_highlights.extend(write_highlights.iter());
16476        }
16477
16478        if all_highlights.is_empty() {
16479            return;
16480        }
16481
16482        // Sort highlights by position
16483        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16484
16485        let target_highlight = match direction {
16486            Direction::Next => {
16487                // Find the first highlight after the current position
16488                all_highlights
16489                    .iter()
16490                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16491            }
16492            Direction::Prev => {
16493                // Find the last highlight before the current position
16494                all_highlights
16495                    .iter()
16496                    .rev()
16497                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16498            }
16499        };
16500
16501        if let Some(highlight) = target_highlight {
16502            let destination = highlight.start.to_point(buffer);
16503            let autoscroll = Autoscroll::center();
16504
16505            self.unfold_ranges(&[destination..destination], false, false, cx);
16506            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16507                s.select_ranges([destination..destination]);
16508            });
16509        }
16510    }
16511
16512    fn go_to_line<T: 'static>(
16513        &mut self,
16514        position: Anchor,
16515        highlight_color: Option<Hsla>,
16516        window: &mut Window,
16517        cx: &mut Context<Self>,
16518    ) {
16519        let snapshot = self.snapshot(window, cx).display_snapshot;
16520        let position = position.to_point(&snapshot.buffer_snapshot());
16521        let start = snapshot
16522            .buffer_snapshot()
16523            .clip_point(Point::new(position.row, 0), Bias::Left);
16524        let end = start + Point::new(1, 0);
16525        let start = snapshot.buffer_snapshot().anchor_before(start);
16526        let end = snapshot.buffer_snapshot().anchor_before(end);
16527
16528        self.highlight_rows::<T>(
16529            start..end,
16530            highlight_color
16531                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16532            Default::default(),
16533            cx,
16534        );
16535
16536        if self.buffer.read(cx).is_singleton() {
16537            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16538        }
16539    }
16540
16541    pub fn go_to_definition(
16542        &mut self,
16543        _: &GoToDefinition,
16544        window: &mut Window,
16545        cx: &mut Context<Self>,
16546    ) -> Task<Result<Navigated>> {
16547        let definition =
16548            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16549        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16550        cx.spawn_in(window, async move |editor, cx| {
16551            if definition.await? == Navigated::Yes {
16552                return Ok(Navigated::Yes);
16553            }
16554            match fallback_strategy {
16555                GoToDefinitionFallback::None => Ok(Navigated::No),
16556                GoToDefinitionFallback::FindAllReferences => {
16557                    match editor.update_in(cx, |editor, window, cx| {
16558                        editor.find_all_references(&FindAllReferences, window, cx)
16559                    })? {
16560                        Some(references) => references.await,
16561                        None => Ok(Navigated::No),
16562                    }
16563                }
16564            }
16565        })
16566    }
16567
16568    pub fn go_to_declaration(
16569        &mut self,
16570        _: &GoToDeclaration,
16571        window: &mut Window,
16572        cx: &mut Context<Self>,
16573    ) -> Task<Result<Navigated>> {
16574        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16575    }
16576
16577    pub fn go_to_declaration_split(
16578        &mut self,
16579        _: &GoToDeclaration,
16580        window: &mut Window,
16581        cx: &mut Context<Self>,
16582    ) -> Task<Result<Navigated>> {
16583        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16584    }
16585
16586    pub fn go_to_implementation(
16587        &mut self,
16588        _: &GoToImplementation,
16589        window: &mut Window,
16590        cx: &mut Context<Self>,
16591    ) -> Task<Result<Navigated>> {
16592        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16593    }
16594
16595    pub fn go_to_implementation_split(
16596        &mut self,
16597        _: &GoToImplementationSplit,
16598        window: &mut Window,
16599        cx: &mut Context<Self>,
16600    ) -> Task<Result<Navigated>> {
16601        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16602    }
16603
16604    pub fn go_to_type_definition(
16605        &mut self,
16606        _: &GoToTypeDefinition,
16607        window: &mut Window,
16608        cx: &mut Context<Self>,
16609    ) -> Task<Result<Navigated>> {
16610        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16611    }
16612
16613    pub fn go_to_definition_split(
16614        &mut self,
16615        _: &GoToDefinitionSplit,
16616        window: &mut Window,
16617        cx: &mut Context<Self>,
16618    ) -> Task<Result<Navigated>> {
16619        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16620    }
16621
16622    pub fn go_to_type_definition_split(
16623        &mut self,
16624        _: &GoToTypeDefinitionSplit,
16625        window: &mut Window,
16626        cx: &mut Context<Self>,
16627    ) -> Task<Result<Navigated>> {
16628        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16629    }
16630
16631    fn go_to_definition_of_kind(
16632        &mut self,
16633        kind: GotoDefinitionKind,
16634        split: bool,
16635        window: &mut Window,
16636        cx: &mut Context<Self>,
16637    ) -> Task<Result<Navigated>> {
16638        let Some(provider) = self.semantics_provider.clone() else {
16639            return Task::ready(Ok(Navigated::No));
16640        };
16641        let head = self
16642            .selections
16643            .newest::<usize>(&self.display_snapshot(cx))
16644            .head();
16645        let buffer = self.buffer.read(cx);
16646        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16647            return Task::ready(Ok(Navigated::No));
16648        };
16649        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16650            return Task::ready(Ok(Navigated::No));
16651        };
16652
16653        cx.spawn_in(window, async move |editor, cx| {
16654            let Some(definitions) = definitions.await? else {
16655                return Ok(Navigated::No);
16656            };
16657            let navigated = editor
16658                .update_in(cx, |editor, window, cx| {
16659                    editor.navigate_to_hover_links(
16660                        Some(kind),
16661                        definitions
16662                            .into_iter()
16663                            .filter(|location| {
16664                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16665                            })
16666                            .map(HoverLink::Text)
16667                            .collect::<Vec<_>>(),
16668                        split,
16669                        window,
16670                        cx,
16671                    )
16672                })?
16673                .await?;
16674            anyhow::Ok(navigated)
16675        })
16676    }
16677
16678    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16679        let selection = self.selections.newest_anchor();
16680        let head = selection.head();
16681        let tail = selection.tail();
16682
16683        let Some((buffer, start_position)) =
16684            self.buffer.read(cx).text_anchor_for_position(head, cx)
16685        else {
16686            return;
16687        };
16688
16689        let end_position = if head != tail {
16690            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16691                return;
16692            };
16693            Some(pos)
16694        } else {
16695            None
16696        };
16697
16698        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16699            let url = if let Some(end_pos) = end_position {
16700                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16701            } else {
16702                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16703            };
16704
16705            if let Some(url) = url {
16706                cx.update(|window, cx| {
16707                    if parse_zed_link(&url, cx).is_some() {
16708                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16709                    } else {
16710                        cx.open_url(&url);
16711                    }
16712                })?;
16713            }
16714
16715            anyhow::Ok(())
16716        });
16717
16718        url_finder.detach();
16719    }
16720
16721    pub fn open_selected_filename(
16722        &mut self,
16723        _: &OpenSelectedFilename,
16724        window: &mut Window,
16725        cx: &mut Context<Self>,
16726    ) {
16727        let Some(workspace) = self.workspace() else {
16728            return;
16729        };
16730
16731        let position = self.selections.newest_anchor().head();
16732
16733        let Some((buffer, buffer_position)) =
16734            self.buffer.read(cx).text_anchor_for_position(position, cx)
16735        else {
16736            return;
16737        };
16738
16739        let project = self.project.clone();
16740
16741        cx.spawn_in(window, async move |_, cx| {
16742            let result = find_file(&buffer, project, buffer_position, cx).await;
16743
16744            if let Some((_, path)) = result {
16745                workspace
16746                    .update_in(cx, |workspace, window, cx| {
16747                        workspace.open_resolved_path(path, window, cx)
16748                    })?
16749                    .await?;
16750            }
16751            anyhow::Ok(())
16752        })
16753        .detach();
16754    }
16755
16756    pub(crate) fn navigate_to_hover_links(
16757        &mut self,
16758        kind: Option<GotoDefinitionKind>,
16759        definitions: Vec<HoverLink>,
16760        split: bool,
16761        window: &mut Window,
16762        cx: &mut Context<Editor>,
16763    ) -> Task<Result<Navigated>> {
16764        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16765        let mut first_url_or_file = None;
16766        let definitions: Vec<_> = definitions
16767            .into_iter()
16768            .filter_map(|def| match def {
16769                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16770                HoverLink::InlayHint(lsp_location, server_id) => {
16771                    let computation =
16772                        self.compute_target_location(lsp_location, server_id, window, cx);
16773                    Some(cx.background_spawn(computation))
16774                }
16775                HoverLink::Url(url) => {
16776                    first_url_or_file = Some(Either::Left(url));
16777                    None
16778                }
16779                HoverLink::File(path) => {
16780                    first_url_or_file = Some(Either::Right(path));
16781                    None
16782                }
16783            })
16784            .collect();
16785
16786        let workspace = self.workspace();
16787
16788        cx.spawn_in(window, async move |editor, cx| {
16789            let locations: Vec<Location> = future::join_all(definitions)
16790                .await
16791                .into_iter()
16792                .filter_map(|location| location.transpose())
16793                .collect::<Result<_>>()
16794                .context("location tasks")?;
16795            let mut locations = cx.update(|_, cx| {
16796                locations
16797                    .into_iter()
16798                    .map(|location| {
16799                        let buffer = location.buffer.read(cx);
16800                        (location.buffer, location.range.to_point(buffer))
16801                    })
16802                    .into_group_map()
16803            })?;
16804            let mut num_locations = 0;
16805            for ranges in locations.values_mut() {
16806                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16807                ranges.dedup();
16808                num_locations += ranges.len();
16809            }
16810
16811            if num_locations > 1 {
16812                let Some(workspace) = workspace else {
16813                    return Ok(Navigated::No);
16814                };
16815
16816                let tab_kind = match kind {
16817                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16818                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16819                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16820                    Some(GotoDefinitionKind::Type) => "Types",
16821                };
16822                let title = editor
16823                    .update_in(cx, |_, _, cx| {
16824                        let target = locations
16825                            .iter()
16826                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16827                            .map(|(buffer, location)| {
16828                                buffer
16829                                    .read(cx)
16830                                    .text_for_range(location.clone())
16831                                    .collect::<String>()
16832                            })
16833                            .filter(|text| !text.contains('\n'))
16834                            .unique()
16835                            .take(3)
16836                            .join(", ");
16837                        if target.is_empty() {
16838                            tab_kind.to_owned()
16839                        } else {
16840                            format!("{tab_kind} for {target}")
16841                        }
16842                    })
16843                    .context("buffer title")?;
16844
16845                let opened = workspace
16846                    .update_in(cx, |workspace, window, cx| {
16847                        Self::open_locations_in_multibuffer(
16848                            workspace,
16849                            locations,
16850                            title,
16851                            split,
16852                            MultibufferSelectionMode::First,
16853                            window,
16854                            cx,
16855                        )
16856                    })
16857                    .is_ok();
16858
16859                anyhow::Ok(Navigated::from_bool(opened))
16860            } else if num_locations == 0 {
16861                // If there is one url or file, open it directly
16862                match first_url_or_file {
16863                    Some(Either::Left(url)) => {
16864                        cx.update(|_, cx| cx.open_url(&url))?;
16865                        Ok(Navigated::Yes)
16866                    }
16867                    Some(Either::Right(path)) => {
16868                        let Some(workspace) = workspace else {
16869                            return Ok(Navigated::No);
16870                        };
16871
16872                        workspace
16873                            .update_in(cx, |workspace, window, cx| {
16874                                workspace.open_resolved_path(path, window, cx)
16875                            })?
16876                            .await?;
16877                        Ok(Navigated::Yes)
16878                    }
16879                    None => Ok(Navigated::No),
16880                }
16881            } else {
16882                let Some(workspace) = workspace else {
16883                    return Ok(Navigated::No);
16884                };
16885
16886                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16887                let target_range = target_ranges.first().unwrap().clone();
16888
16889                editor.update_in(cx, |editor, window, cx| {
16890                    let range = target_range.to_point(target_buffer.read(cx));
16891                    let range = editor.range_for_match(&range, false);
16892                    let range = collapse_multiline_range(range);
16893
16894                    if !split
16895                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16896                    {
16897                        editor.go_to_singleton_buffer_range(range, window, cx);
16898                    } else {
16899                        let pane = workspace.read(cx).active_pane().clone();
16900                        window.defer(cx, move |window, cx| {
16901                            let target_editor: Entity<Self> =
16902                                workspace.update(cx, |workspace, cx| {
16903                                    let pane = if split {
16904                                        workspace.adjacent_pane(window, cx)
16905                                    } else {
16906                                        workspace.active_pane().clone()
16907                                    };
16908
16909                                    workspace.open_project_item(
16910                                        pane,
16911                                        target_buffer.clone(),
16912                                        true,
16913                                        true,
16914                                        window,
16915                                        cx,
16916                                    )
16917                                });
16918                            target_editor.update(cx, |target_editor, cx| {
16919                                // When selecting a definition in a different buffer, disable the nav history
16920                                // to avoid creating a history entry at the previous cursor location.
16921                                pane.update(cx, |pane, _| pane.disable_history());
16922                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16923                                pane.update(cx, |pane, _| pane.enable_history());
16924                            });
16925                        });
16926                    }
16927                    Navigated::Yes
16928                })
16929            }
16930        })
16931    }
16932
16933    fn compute_target_location(
16934        &self,
16935        lsp_location: lsp::Location,
16936        server_id: LanguageServerId,
16937        window: &mut Window,
16938        cx: &mut Context<Self>,
16939    ) -> Task<anyhow::Result<Option<Location>>> {
16940        let Some(project) = self.project.clone() else {
16941            return Task::ready(Ok(None));
16942        };
16943
16944        cx.spawn_in(window, async move |editor, cx| {
16945            let location_task = editor.update(cx, |_, cx| {
16946                project.update(cx, |project, cx| {
16947                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16948                })
16949            })?;
16950            let location = Some({
16951                let target_buffer_handle = location_task.await.context("open local buffer")?;
16952                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16953                    let target_start = target_buffer
16954                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16955                    let target_end = target_buffer
16956                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16957                    target_buffer.anchor_after(target_start)
16958                        ..target_buffer.anchor_before(target_end)
16959                })?;
16960                Location {
16961                    buffer: target_buffer_handle,
16962                    range,
16963                }
16964            });
16965            Ok(location)
16966        })
16967    }
16968
16969    fn go_to_next_reference(
16970        &mut self,
16971        _: &GoToNextReference,
16972        window: &mut Window,
16973        cx: &mut Context<Self>,
16974    ) {
16975        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16976        if let Some(task) = task {
16977            task.detach();
16978        };
16979    }
16980
16981    fn go_to_prev_reference(
16982        &mut self,
16983        _: &GoToPreviousReference,
16984        window: &mut Window,
16985        cx: &mut Context<Self>,
16986    ) {
16987        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16988        if let Some(task) = task {
16989            task.detach();
16990        };
16991    }
16992
16993    pub fn go_to_reference_before_or_after_position(
16994        &mut self,
16995        direction: Direction,
16996        count: usize,
16997        window: &mut Window,
16998        cx: &mut Context<Self>,
16999    ) -> Option<Task<Result<()>>> {
17000        let selection = self.selections.newest_anchor();
17001        let head = selection.head();
17002
17003        let multi_buffer = self.buffer.read(cx);
17004
17005        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17006        let workspace = self.workspace()?;
17007        let project = workspace.read(cx).project().clone();
17008        let references =
17009            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17010        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17011            let Some(locations) = references.await? else {
17012                return Ok(());
17013            };
17014
17015            if locations.is_empty() {
17016                // totally normal - the cursor may be on something which is not
17017                // a symbol (e.g. a keyword)
17018                log::info!("no references found under cursor");
17019                return Ok(());
17020            }
17021
17022            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17023
17024            let multi_buffer_snapshot =
17025                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
17026
17027            let (locations, current_location_index) =
17028                multi_buffer.update(cx, |multi_buffer, cx| {
17029                    let mut locations = locations
17030                        .into_iter()
17031                        .filter_map(|loc| {
17032                            let start = multi_buffer.buffer_anchor_to_anchor(
17033                                &loc.buffer,
17034                                loc.range.start,
17035                                cx,
17036                            )?;
17037                            let end = multi_buffer.buffer_anchor_to_anchor(
17038                                &loc.buffer,
17039                                loc.range.end,
17040                                cx,
17041                            )?;
17042                            Some(start..end)
17043                        })
17044                        .collect::<Vec<_>>();
17045
17046                    // There is an O(n) implementation, but given this list will be
17047                    // small (usually <100 items), the extra O(log(n)) factor isn't
17048                    // worth the (surprisingly large amount of) extra complexity.
17049                    locations
17050                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17051
17052                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17053
17054                    let current_location_index = locations.iter().position(|loc| {
17055                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17056                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17057                    });
17058
17059                    (locations, current_location_index)
17060                })?;
17061
17062            let Some(current_location_index) = current_location_index else {
17063                // This indicates something has gone wrong, because we already
17064                // handle the "no references" case above
17065                log::error!(
17066                    "failed to find current reference under cursor. Total references: {}",
17067                    locations.len()
17068                );
17069                return Ok(());
17070            };
17071
17072            let destination_location_index = match direction {
17073                Direction::Next => (current_location_index + count) % locations.len(),
17074                Direction::Prev => {
17075                    (current_location_index + locations.len() - count % locations.len())
17076                        % locations.len()
17077                }
17078            };
17079
17080            // TODO(cameron): is this needed?
17081            // the thinking is to avoid "jumping to the current location" (avoid
17082            // polluting "jumplist" in vim terms)
17083            if current_location_index == destination_location_index {
17084                return Ok(());
17085            }
17086
17087            let Range { start, end } = locations[destination_location_index];
17088
17089            editor.update_in(cx, |editor, window, cx| {
17090                let effects = SelectionEffects::default();
17091
17092                editor.unfold_ranges(&[start..end], false, false, cx);
17093                editor.change_selections(effects, window, cx, |s| {
17094                    s.select_ranges([start..start]);
17095                });
17096            })?;
17097
17098            Ok(())
17099        }))
17100    }
17101
17102    pub fn find_all_references(
17103        &mut self,
17104        _: &FindAllReferences,
17105        window: &mut Window,
17106        cx: &mut Context<Self>,
17107    ) -> Option<Task<Result<Navigated>>> {
17108        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
17109        let multi_buffer = self.buffer.read(cx);
17110        let head = selection.head();
17111
17112        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17113        let head_anchor = multi_buffer_snapshot.anchor_at(
17114            head,
17115            if head < selection.tail() {
17116                Bias::Right
17117            } else {
17118                Bias::Left
17119            },
17120        );
17121
17122        match self
17123            .find_all_references_task_sources
17124            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17125        {
17126            Ok(_) => {
17127                log::info!(
17128                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17129                );
17130                return None;
17131            }
17132            Err(i) => {
17133                self.find_all_references_task_sources.insert(i, head_anchor);
17134            }
17135        }
17136
17137        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17138        let workspace = self.workspace()?;
17139        let project = workspace.read(cx).project().clone();
17140        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17141        Some(cx.spawn_in(window, async move |editor, cx| {
17142            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17143                if let Ok(i) = editor
17144                    .find_all_references_task_sources
17145                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17146                {
17147                    editor.find_all_references_task_sources.remove(i);
17148                }
17149            });
17150
17151            let Some(locations) = references.await? else {
17152                return anyhow::Ok(Navigated::No);
17153            };
17154            let mut locations = cx.update(|_, cx| {
17155                locations
17156                    .into_iter()
17157                    .map(|location| {
17158                        let buffer = location.buffer.read(cx);
17159                        (location.buffer, location.range.to_point(buffer))
17160                    })
17161                    .into_group_map()
17162            })?;
17163            if locations.is_empty() {
17164                return anyhow::Ok(Navigated::No);
17165            }
17166            for ranges in locations.values_mut() {
17167                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17168                ranges.dedup();
17169            }
17170
17171            workspace.update_in(cx, |workspace, window, cx| {
17172                let target = locations
17173                    .iter()
17174                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17175                    .map(|(buffer, location)| {
17176                        buffer
17177                            .read(cx)
17178                            .text_for_range(location.clone())
17179                            .collect::<String>()
17180                    })
17181                    .filter(|text| !text.contains('\n'))
17182                    .unique()
17183                    .take(3)
17184                    .join(", ");
17185                let title = if target.is_empty() {
17186                    "References".to_owned()
17187                } else {
17188                    format!("References to {target}")
17189                };
17190                Self::open_locations_in_multibuffer(
17191                    workspace,
17192                    locations,
17193                    title,
17194                    false,
17195                    MultibufferSelectionMode::First,
17196                    window,
17197                    cx,
17198                );
17199                Navigated::Yes
17200            })
17201        }))
17202    }
17203
17204    /// Opens a multibuffer with the given project locations in it
17205    pub fn open_locations_in_multibuffer(
17206        workspace: &mut Workspace,
17207        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17208        title: String,
17209        split: bool,
17210        multibuffer_selection_mode: MultibufferSelectionMode,
17211        window: &mut Window,
17212        cx: &mut Context<Workspace>,
17213    ) {
17214        if locations.is_empty() {
17215            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17216            return;
17217        }
17218
17219        let capability = workspace.project().read(cx).capability();
17220        let mut ranges = <Vec<Range<Anchor>>>::new();
17221
17222        // a key to find existing multibuffer editors with the same set of locations
17223        // to prevent us from opening more and more multibuffer tabs for searches and the like
17224        let mut key = (title.clone(), vec![]);
17225        let excerpt_buffer = cx.new(|cx| {
17226            let key = &mut key.1;
17227            let mut multibuffer = MultiBuffer::new(capability);
17228            for (buffer, mut ranges_for_buffer) in locations {
17229                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17230                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17231                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17232                    PathKey::for_buffer(&buffer, cx),
17233                    buffer.clone(),
17234                    ranges_for_buffer,
17235                    multibuffer_context_lines(cx),
17236                    cx,
17237                );
17238                ranges.extend(new_ranges)
17239            }
17240
17241            multibuffer.with_title(title)
17242        });
17243        let existing = workspace.active_pane().update(cx, |pane, cx| {
17244            pane.items()
17245                .filter_map(|item| item.downcast::<Editor>())
17246                .find(|editor| {
17247                    editor
17248                        .read(cx)
17249                        .lookup_key
17250                        .as_ref()
17251                        .and_then(|it| {
17252                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17253                        })
17254                        .is_some_and(|it| *it == key)
17255                })
17256        });
17257        let editor = existing.unwrap_or_else(|| {
17258            cx.new(|cx| {
17259                let mut editor = Editor::for_multibuffer(
17260                    excerpt_buffer,
17261                    Some(workspace.project().clone()),
17262                    window,
17263                    cx,
17264                );
17265                editor.lookup_key = Some(Box::new(key));
17266                editor
17267            })
17268        });
17269        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17270            MultibufferSelectionMode::First => {
17271                if let Some(first_range) = ranges.first() {
17272                    editor.change_selections(
17273                        SelectionEffects::no_scroll(),
17274                        window,
17275                        cx,
17276                        |selections| {
17277                            selections.clear_disjoint();
17278                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17279                        },
17280                    );
17281                }
17282                editor.highlight_background::<Self>(
17283                    &ranges,
17284                    |theme| theme.colors().editor_highlighted_line_background,
17285                    cx,
17286                );
17287            }
17288            MultibufferSelectionMode::All => {
17289                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17290                    selections.clear_disjoint();
17291                    selections.select_anchor_ranges(ranges);
17292                });
17293            }
17294        });
17295
17296        let item = Box::new(editor);
17297        let item_id = item.item_id();
17298
17299        if split {
17300            let pane = workspace.adjacent_pane(window, cx);
17301            workspace.add_item(pane, item, None, true, true, window, cx);
17302        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17303            let (preview_item_id, preview_item_idx) =
17304                workspace.active_pane().read_with(cx, |pane, _| {
17305                    (pane.preview_item_id(), pane.preview_item_idx())
17306                });
17307
17308            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17309
17310            if let Some(preview_item_id) = preview_item_id {
17311                workspace.active_pane().update(cx, |pane, cx| {
17312                    pane.remove_item(preview_item_id, false, false, window, cx);
17313                });
17314            }
17315        } else {
17316            workspace.add_item_to_active_pane(item, None, true, window, cx);
17317        }
17318        workspace.active_pane().update(cx, |pane, cx| {
17319            pane.set_preview_item_id(Some(item_id), cx);
17320        });
17321    }
17322
17323    pub fn rename(
17324        &mut self,
17325        _: &Rename,
17326        window: &mut Window,
17327        cx: &mut Context<Self>,
17328    ) -> Option<Task<Result<()>>> {
17329        use language::ToOffset as _;
17330
17331        let provider = self.semantics_provider.clone()?;
17332        let selection = self.selections.newest_anchor().clone();
17333        let (cursor_buffer, cursor_buffer_position) = self
17334            .buffer
17335            .read(cx)
17336            .text_anchor_for_position(selection.head(), cx)?;
17337        let (tail_buffer, cursor_buffer_position_end) = self
17338            .buffer
17339            .read(cx)
17340            .text_anchor_for_position(selection.tail(), cx)?;
17341        if tail_buffer != cursor_buffer {
17342            return None;
17343        }
17344
17345        let snapshot = cursor_buffer.read(cx).snapshot();
17346        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17347        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17348        let prepare_rename = provider
17349            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17350            .unwrap_or_else(|| Task::ready(Ok(None)));
17351        drop(snapshot);
17352
17353        Some(cx.spawn_in(window, async move |this, cx| {
17354            let rename_range = if let Some(range) = prepare_rename.await? {
17355                Some(range)
17356            } else {
17357                this.update(cx, |this, cx| {
17358                    let buffer = this.buffer.read(cx).snapshot(cx);
17359                    let mut buffer_highlights = this
17360                        .document_highlights_for_position(selection.head(), &buffer)
17361                        .filter(|highlight| {
17362                            highlight.start.excerpt_id == selection.head().excerpt_id
17363                                && highlight.end.excerpt_id == selection.head().excerpt_id
17364                        });
17365                    buffer_highlights
17366                        .next()
17367                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17368                })?
17369            };
17370            if let Some(rename_range) = rename_range {
17371                this.update_in(cx, |this, window, cx| {
17372                    let snapshot = cursor_buffer.read(cx).snapshot();
17373                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17374                    let cursor_offset_in_rename_range =
17375                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17376                    let cursor_offset_in_rename_range_end =
17377                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17378
17379                    this.take_rename(false, window, cx);
17380                    let buffer = this.buffer.read(cx).read(cx);
17381                    let cursor_offset = selection.head().to_offset(&buffer);
17382                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17383                    let rename_end = rename_start + rename_buffer_range.len();
17384                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17385                    let mut old_highlight_id = None;
17386                    let old_name: Arc<str> = buffer
17387                        .chunks(rename_start..rename_end, true)
17388                        .map(|chunk| {
17389                            if old_highlight_id.is_none() {
17390                                old_highlight_id = chunk.syntax_highlight_id;
17391                            }
17392                            chunk.text
17393                        })
17394                        .collect::<String>()
17395                        .into();
17396
17397                    drop(buffer);
17398
17399                    // Position the selection in the rename editor so that it matches the current selection.
17400                    this.show_local_selections = false;
17401                    let rename_editor = cx.new(|cx| {
17402                        let mut editor = Editor::single_line(window, cx);
17403                        editor.buffer.update(cx, |buffer, cx| {
17404                            buffer.edit([(0..0, old_name.clone())], None, cx)
17405                        });
17406                        let rename_selection_range = match cursor_offset_in_rename_range
17407                            .cmp(&cursor_offset_in_rename_range_end)
17408                        {
17409                            Ordering::Equal => {
17410                                editor.select_all(&SelectAll, window, cx);
17411                                return editor;
17412                            }
17413                            Ordering::Less => {
17414                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17415                            }
17416                            Ordering::Greater => {
17417                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17418                            }
17419                        };
17420                        if rename_selection_range.end > old_name.len() {
17421                            editor.select_all(&SelectAll, window, cx);
17422                        } else {
17423                            editor.change_selections(Default::default(), window, cx, |s| {
17424                                s.select_ranges([rename_selection_range]);
17425                            });
17426                        }
17427                        editor
17428                    });
17429                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17430                        if e == &EditorEvent::Focused {
17431                            cx.emit(EditorEvent::FocusedIn)
17432                        }
17433                    })
17434                    .detach();
17435
17436                    let write_highlights =
17437                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17438                    let read_highlights =
17439                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17440                    let ranges = write_highlights
17441                        .iter()
17442                        .flat_map(|(_, ranges)| ranges.iter())
17443                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17444                        .cloned()
17445                        .collect();
17446
17447                    this.highlight_text::<Rename>(
17448                        ranges,
17449                        HighlightStyle {
17450                            fade_out: Some(0.6),
17451                            ..Default::default()
17452                        },
17453                        cx,
17454                    );
17455                    let rename_focus_handle = rename_editor.focus_handle(cx);
17456                    window.focus(&rename_focus_handle);
17457                    let block_id = this.insert_blocks(
17458                        [BlockProperties {
17459                            style: BlockStyle::Flex,
17460                            placement: BlockPlacement::Below(range.start),
17461                            height: Some(1),
17462                            render: Arc::new({
17463                                let rename_editor = rename_editor.clone();
17464                                move |cx: &mut BlockContext| {
17465                                    let mut text_style = cx.editor_style.text.clone();
17466                                    if let Some(highlight_style) = old_highlight_id
17467                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17468                                    {
17469                                        text_style = text_style.highlight(highlight_style);
17470                                    }
17471                                    div()
17472                                        .block_mouse_except_scroll()
17473                                        .pl(cx.anchor_x)
17474                                        .child(EditorElement::new(
17475                                            &rename_editor,
17476                                            EditorStyle {
17477                                                background: cx.theme().system().transparent,
17478                                                local_player: cx.editor_style.local_player,
17479                                                text: text_style,
17480                                                scrollbar_width: cx.editor_style.scrollbar_width,
17481                                                syntax: cx.editor_style.syntax.clone(),
17482                                                status: cx.editor_style.status.clone(),
17483                                                inlay_hints_style: HighlightStyle {
17484                                                    font_weight: Some(FontWeight::BOLD),
17485                                                    ..make_inlay_hints_style(cx.app)
17486                                                },
17487                                                edit_prediction_styles: make_suggestion_styles(
17488                                                    cx.app,
17489                                                ),
17490                                                ..EditorStyle::default()
17491                                            },
17492                                        ))
17493                                        .into_any_element()
17494                                }
17495                            }),
17496                            priority: 0,
17497                        }],
17498                        Some(Autoscroll::fit()),
17499                        cx,
17500                    )[0];
17501                    this.pending_rename = Some(RenameState {
17502                        range,
17503                        old_name,
17504                        editor: rename_editor,
17505                        block_id,
17506                    });
17507                })?;
17508            }
17509
17510            Ok(())
17511        }))
17512    }
17513
17514    pub fn confirm_rename(
17515        &mut self,
17516        _: &ConfirmRename,
17517        window: &mut Window,
17518        cx: &mut Context<Self>,
17519    ) -> Option<Task<Result<()>>> {
17520        let rename = self.take_rename(false, window, cx)?;
17521        let workspace = self.workspace()?.downgrade();
17522        let (buffer, start) = self
17523            .buffer
17524            .read(cx)
17525            .text_anchor_for_position(rename.range.start, cx)?;
17526        let (end_buffer, _) = self
17527            .buffer
17528            .read(cx)
17529            .text_anchor_for_position(rename.range.end, cx)?;
17530        if buffer != end_buffer {
17531            return None;
17532        }
17533
17534        let old_name = rename.old_name;
17535        let new_name = rename.editor.read(cx).text(cx);
17536
17537        let rename = self.semantics_provider.as_ref()?.perform_rename(
17538            &buffer,
17539            start,
17540            new_name.clone(),
17541            cx,
17542        )?;
17543
17544        Some(cx.spawn_in(window, async move |editor, cx| {
17545            let project_transaction = rename.await?;
17546            Self::open_project_transaction(
17547                &editor,
17548                workspace,
17549                project_transaction,
17550                format!("Rename: {}{}", old_name, new_name),
17551                cx,
17552            )
17553            .await?;
17554
17555            editor.update(cx, |editor, cx| {
17556                editor.refresh_document_highlights(cx);
17557            })?;
17558            Ok(())
17559        }))
17560    }
17561
17562    fn take_rename(
17563        &mut self,
17564        moving_cursor: bool,
17565        window: &mut Window,
17566        cx: &mut Context<Self>,
17567    ) -> Option<RenameState> {
17568        let rename = self.pending_rename.take()?;
17569        if rename.editor.focus_handle(cx).is_focused(window) {
17570            window.focus(&self.focus_handle);
17571        }
17572
17573        self.remove_blocks(
17574            [rename.block_id].into_iter().collect(),
17575            Some(Autoscroll::fit()),
17576            cx,
17577        );
17578        self.clear_highlights::<Rename>(cx);
17579        self.show_local_selections = true;
17580
17581        if moving_cursor {
17582            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17583                editor
17584                    .selections
17585                    .newest::<usize>(&editor.display_snapshot(cx))
17586                    .head()
17587            });
17588
17589            // Update the selection to match the position of the selection inside
17590            // the rename editor.
17591            let snapshot = self.buffer.read(cx).read(cx);
17592            let rename_range = rename.range.to_offset(&snapshot);
17593            let cursor_in_editor = snapshot
17594                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17595                .min(rename_range.end);
17596            drop(snapshot);
17597
17598            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17599                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17600            });
17601        } else {
17602            self.refresh_document_highlights(cx);
17603        }
17604
17605        Some(rename)
17606    }
17607
17608    pub fn pending_rename(&self) -> Option<&RenameState> {
17609        self.pending_rename.as_ref()
17610    }
17611
17612    fn format(
17613        &mut self,
17614        _: &Format,
17615        window: &mut Window,
17616        cx: &mut Context<Self>,
17617    ) -> Option<Task<Result<()>>> {
17618        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17619
17620        let project = match &self.project {
17621            Some(project) => project.clone(),
17622            None => return None,
17623        };
17624
17625        Some(self.perform_format(
17626            project,
17627            FormatTrigger::Manual,
17628            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17629            window,
17630            cx,
17631        ))
17632    }
17633
17634    fn format_selections(
17635        &mut self,
17636        _: &FormatSelections,
17637        window: &mut Window,
17638        cx: &mut Context<Self>,
17639    ) -> Option<Task<Result<()>>> {
17640        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17641
17642        let project = match &self.project {
17643            Some(project) => project.clone(),
17644            None => return None,
17645        };
17646
17647        let ranges = self
17648            .selections
17649            .all_adjusted(&self.display_snapshot(cx))
17650            .into_iter()
17651            .map(|selection| selection.range())
17652            .collect_vec();
17653
17654        Some(self.perform_format(
17655            project,
17656            FormatTrigger::Manual,
17657            FormatTarget::Ranges(ranges),
17658            window,
17659            cx,
17660        ))
17661    }
17662
17663    fn perform_format(
17664        &mut self,
17665        project: Entity<Project>,
17666        trigger: FormatTrigger,
17667        target: FormatTarget,
17668        window: &mut Window,
17669        cx: &mut Context<Self>,
17670    ) -> Task<Result<()>> {
17671        let buffer = self.buffer.clone();
17672        let (buffers, target) = match target {
17673            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17674            FormatTarget::Ranges(selection_ranges) => {
17675                let multi_buffer = buffer.read(cx);
17676                let snapshot = multi_buffer.read(cx);
17677                let mut buffers = HashSet::default();
17678                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17679                    BTreeMap::new();
17680                for selection_range in selection_ranges {
17681                    for (buffer, buffer_range, _) in
17682                        snapshot.range_to_buffer_ranges(selection_range)
17683                    {
17684                        let buffer_id = buffer.remote_id();
17685                        let start = buffer.anchor_before(buffer_range.start);
17686                        let end = buffer.anchor_after(buffer_range.end);
17687                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17688                        buffer_id_to_ranges
17689                            .entry(buffer_id)
17690                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17691                            .or_insert_with(|| vec![start..end]);
17692                    }
17693                }
17694                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17695            }
17696        };
17697
17698        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17699        let selections_prev = transaction_id_prev
17700            .and_then(|transaction_id_prev| {
17701                // default to selections as they were after the last edit, if we have them,
17702                // instead of how they are now.
17703                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17704                // will take you back to where you made the last edit, instead of staying where you scrolled
17705                self.selection_history
17706                    .transaction(transaction_id_prev)
17707                    .map(|t| t.0.clone())
17708            })
17709            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17710
17711        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17712        let format = project.update(cx, |project, cx| {
17713            project.format(buffers, target, true, trigger, cx)
17714        });
17715
17716        cx.spawn_in(window, async move |editor, cx| {
17717            let transaction = futures::select_biased! {
17718                transaction = format.log_err().fuse() => transaction,
17719                () = timeout => {
17720                    log::warn!("timed out waiting for formatting");
17721                    None
17722                }
17723            };
17724
17725            buffer
17726                .update(cx, |buffer, cx| {
17727                    if let Some(transaction) = transaction
17728                        && !buffer.is_singleton()
17729                    {
17730                        buffer.push_transaction(&transaction.0, cx);
17731                    }
17732                    cx.notify();
17733                })
17734                .ok();
17735
17736            if let Some(transaction_id_now) =
17737                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17738            {
17739                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17740                if has_new_transaction {
17741                    _ = editor.update(cx, |editor, _| {
17742                        editor
17743                            .selection_history
17744                            .insert_transaction(transaction_id_now, selections_prev);
17745                    });
17746                }
17747            }
17748
17749            Ok(())
17750        })
17751    }
17752
17753    fn organize_imports(
17754        &mut self,
17755        _: &OrganizeImports,
17756        window: &mut Window,
17757        cx: &mut Context<Self>,
17758    ) -> Option<Task<Result<()>>> {
17759        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17760        let project = match &self.project {
17761            Some(project) => project.clone(),
17762            None => return None,
17763        };
17764        Some(self.perform_code_action_kind(
17765            project,
17766            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17767            window,
17768            cx,
17769        ))
17770    }
17771
17772    fn perform_code_action_kind(
17773        &mut self,
17774        project: Entity<Project>,
17775        kind: CodeActionKind,
17776        window: &mut Window,
17777        cx: &mut Context<Self>,
17778    ) -> Task<Result<()>> {
17779        let buffer = self.buffer.clone();
17780        let buffers = buffer.read(cx).all_buffers();
17781        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17782        let apply_action = project.update(cx, |project, cx| {
17783            project.apply_code_action_kind(buffers, kind, true, cx)
17784        });
17785        cx.spawn_in(window, async move |_, cx| {
17786            let transaction = futures::select_biased! {
17787                () = timeout => {
17788                    log::warn!("timed out waiting for executing code action");
17789                    None
17790                }
17791                transaction = apply_action.log_err().fuse() => transaction,
17792            };
17793            buffer
17794                .update(cx, |buffer, cx| {
17795                    // check if we need this
17796                    if let Some(transaction) = transaction
17797                        && !buffer.is_singleton()
17798                    {
17799                        buffer.push_transaction(&transaction.0, cx);
17800                    }
17801                    cx.notify();
17802                })
17803                .ok();
17804            Ok(())
17805        })
17806    }
17807
17808    pub fn restart_language_server(
17809        &mut self,
17810        _: &RestartLanguageServer,
17811        _: &mut Window,
17812        cx: &mut Context<Self>,
17813    ) {
17814        if let Some(project) = self.project.clone() {
17815            self.buffer.update(cx, |multi_buffer, cx| {
17816                project.update(cx, |project, cx| {
17817                    project.restart_language_servers_for_buffers(
17818                        multi_buffer.all_buffers().into_iter().collect(),
17819                        HashSet::default(),
17820                        cx,
17821                    );
17822                });
17823            })
17824        }
17825    }
17826
17827    pub fn stop_language_server(
17828        &mut self,
17829        _: &StopLanguageServer,
17830        _: &mut Window,
17831        cx: &mut Context<Self>,
17832    ) {
17833        if let Some(project) = self.project.clone() {
17834            self.buffer.update(cx, |multi_buffer, cx| {
17835                project.update(cx, |project, cx| {
17836                    project.stop_language_servers_for_buffers(
17837                        multi_buffer.all_buffers().into_iter().collect(),
17838                        HashSet::default(),
17839                        cx,
17840                    );
17841                });
17842            });
17843            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17844        }
17845    }
17846
17847    fn cancel_language_server_work(
17848        workspace: &mut Workspace,
17849        _: &actions::CancelLanguageServerWork,
17850        _: &mut Window,
17851        cx: &mut Context<Workspace>,
17852    ) {
17853        let project = workspace.project();
17854        let buffers = workspace
17855            .active_item(cx)
17856            .and_then(|item| item.act_as::<Editor>(cx))
17857            .map_or(HashSet::default(), |editor| {
17858                editor.read(cx).buffer.read(cx).all_buffers()
17859            });
17860        project.update(cx, |project, cx| {
17861            project.cancel_language_server_work_for_buffers(buffers, cx);
17862        });
17863    }
17864
17865    fn show_character_palette(
17866        &mut self,
17867        _: &ShowCharacterPalette,
17868        window: &mut Window,
17869        _: &mut Context<Self>,
17870    ) {
17871        window.show_character_palette();
17872    }
17873
17874    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17875        if !self.diagnostics_enabled() {
17876            return;
17877        }
17878
17879        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17880            let buffer = self.buffer.read(cx).snapshot(cx);
17881            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17882            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17883            let is_valid = buffer
17884                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17885                .any(|entry| {
17886                    entry.diagnostic.is_primary
17887                        && !entry.range.is_empty()
17888                        && entry.range.start == primary_range_start
17889                        && entry.diagnostic.message == active_diagnostics.active_message
17890                });
17891
17892            if !is_valid {
17893                self.dismiss_diagnostics(cx);
17894            }
17895        }
17896    }
17897
17898    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17899        match &self.active_diagnostics {
17900            ActiveDiagnostic::Group(group) => Some(group),
17901            _ => None,
17902        }
17903    }
17904
17905    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17906        if !self.diagnostics_enabled() {
17907            return;
17908        }
17909        self.dismiss_diagnostics(cx);
17910        self.active_diagnostics = ActiveDiagnostic::All;
17911    }
17912
17913    fn activate_diagnostics(
17914        &mut self,
17915        buffer_id: BufferId,
17916        diagnostic: DiagnosticEntryRef<'_, usize>,
17917        window: &mut Window,
17918        cx: &mut Context<Self>,
17919    ) {
17920        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17921            return;
17922        }
17923        self.dismiss_diagnostics(cx);
17924        let snapshot = self.snapshot(window, cx);
17925        let buffer = self.buffer.read(cx).snapshot(cx);
17926        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17927            return;
17928        };
17929
17930        let diagnostic_group = buffer
17931            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17932            .collect::<Vec<_>>();
17933
17934        let blocks =
17935            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17936
17937        let blocks = self.display_map.update(cx, |display_map, cx| {
17938            display_map.insert_blocks(blocks, cx).into_iter().collect()
17939        });
17940        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17941            active_range: buffer.anchor_before(diagnostic.range.start)
17942                ..buffer.anchor_after(diagnostic.range.end),
17943            active_message: diagnostic.diagnostic.message.clone(),
17944            group_id: diagnostic.diagnostic.group_id,
17945            blocks,
17946        });
17947        cx.notify();
17948    }
17949
17950    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17951        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17952            return;
17953        };
17954
17955        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17956        if let ActiveDiagnostic::Group(group) = prev {
17957            self.display_map.update(cx, |display_map, cx| {
17958                display_map.remove_blocks(group.blocks, cx);
17959            });
17960            cx.notify();
17961        }
17962    }
17963
17964    /// Disable inline diagnostics rendering for this editor.
17965    pub fn disable_inline_diagnostics(&mut self) {
17966        self.inline_diagnostics_enabled = false;
17967        self.inline_diagnostics_update = Task::ready(());
17968        self.inline_diagnostics.clear();
17969    }
17970
17971    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17972        self.diagnostics_enabled = false;
17973        self.dismiss_diagnostics(cx);
17974        self.inline_diagnostics_update = Task::ready(());
17975        self.inline_diagnostics.clear();
17976    }
17977
17978    pub fn disable_word_completions(&mut self) {
17979        self.word_completions_enabled = false;
17980    }
17981
17982    pub fn diagnostics_enabled(&self) -> bool {
17983        self.diagnostics_enabled && self.mode.is_full()
17984    }
17985
17986    pub fn inline_diagnostics_enabled(&self) -> bool {
17987        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17988    }
17989
17990    pub fn show_inline_diagnostics(&self) -> bool {
17991        self.show_inline_diagnostics
17992    }
17993
17994    pub fn toggle_inline_diagnostics(
17995        &mut self,
17996        _: &ToggleInlineDiagnostics,
17997        window: &mut Window,
17998        cx: &mut Context<Editor>,
17999    ) {
18000        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18001        self.refresh_inline_diagnostics(false, window, cx);
18002    }
18003
18004    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18005        self.diagnostics_max_severity = severity;
18006        self.display_map.update(cx, |display_map, _| {
18007            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18008        });
18009    }
18010
18011    pub fn toggle_diagnostics(
18012        &mut self,
18013        _: &ToggleDiagnostics,
18014        window: &mut Window,
18015        cx: &mut Context<Editor>,
18016    ) {
18017        if !self.diagnostics_enabled() {
18018            return;
18019        }
18020
18021        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18022            EditorSettings::get_global(cx)
18023                .diagnostics_max_severity
18024                .filter(|severity| severity != &DiagnosticSeverity::Off)
18025                .unwrap_or(DiagnosticSeverity::Hint)
18026        } else {
18027            DiagnosticSeverity::Off
18028        };
18029        self.set_max_diagnostics_severity(new_severity, cx);
18030        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18031            self.active_diagnostics = ActiveDiagnostic::None;
18032            self.inline_diagnostics_update = Task::ready(());
18033            self.inline_diagnostics.clear();
18034        } else {
18035            self.refresh_inline_diagnostics(false, window, cx);
18036        }
18037
18038        cx.notify();
18039    }
18040
18041    pub fn toggle_minimap(
18042        &mut self,
18043        _: &ToggleMinimap,
18044        window: &mut Window,
18045        cx: &mut Context<Editor>,
18046    ) {
18047        if self.supports_minimap(cx) {
18048            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18049        }
18050    }
18051
18052    fn refresh_inline_diagnostics(
18053        &mut self,
18054        debounce: bool,
18055        window: &mut Window,
18056        cx: &mut Context<Self>,
18057    ) {
18058        let max_severity = ProjectSettings::get_global(cx)
18059            .diagnostics
18060            .inline
18061            .max_severity
18062            .unwrap_or(self.diagnostics_max_severity);
18063
18064        if !self.inline_diagnostics_enabled()
18065            || !self.diagnostics_enabled()
18066            || !self.show_inline_diagnostics
18067            || max_severity == DiagnosticSeverity::Off
18068        {
18069            self.inline_diagnostics_update = Task::ready(());
18070            self.inline_diagnostics.clear();
18071            return;
18072        }
18073
18074        let debounce_ms = ProjectSettings::get_global(cx)
18075            .diagnostics
18076            .inline
18077            .update_debounce_ms;
18078        let debounce = if debounce && debounce_ms > 0 {
18079            Some(Duration::from_millis(debounce_ms))
18080        } else {
18081            None
18082        };
18083        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18084            if let Some(debounce) = debounce {
18085                cx.background_executor().timer(debounce).await;
18086            }
18087            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18088                editor
18089                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18090                    .ok()
18091            }) else {
18092                return;
18093            };
18094
18095            let new_inline_diagnostics = cx
18096                .background_spawn(async move {
18097                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18098                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
18099                        let message = diagnostic_entry
18100                            .diagnostic
18101                            .message
18102                            .split_once('\n')
18103                            .map(|(line, _)| line)
18104                            .map(SharedString::new)
18105                            .unwrap_or_else(|| {
18106                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18107                            });
18108                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18109                        let (Ok(i) | Err(i)) = inline_diagnostics
18110                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18111                        inline_diagnostics.insert(
18112                            i,
18113                            (
18114                                start_anchor,
18115                                InlineDiagnostic {
18116                                    message,
18117                                    group_id: diagnostic_entry.diagnostic.group_id,
18118                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18119                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18120                                    severity: diagnostic_entry.diagnostic.severity,
18121                                },
18122                            ),
18123                        );
18124                    }
18125                    inline_diagnostics
18126                })
18127                .await;
18128
18129            editor
18130                .update(cx, |editor, cx| {
18131                    editor.inline_diagnostics = new_inline_diagnostics;
18132                    cx.notify();
18133                })
18134                .ok();
18135        });
18136    }
18137
18138    fn pull_diagnostics(
18139        &mut self,
18140        buffer_id: Option<BufferId>,
18141        window: &Window,
18142        cx: &mut Context<Self>,
18143    ) -> Option<()> {
18144        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18145            return None;
18146        }
18147        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18148            .diagnostics
18149            .lsp_pull_diagnostics;
18150        if !pull_diagnostics_settings.enabled {
18151            return None;
18152        }
18153        let project = self.project()?.downgrade();
18154        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18155        let mut buffers = self.buffer.read(cx).all_buffers();
18156        buffers.retain(|buffer| {
18157            let buffer_id_to_retain = buffer.read(cx).remote_id();
18158            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18159                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18160        });
18161        if buffers.is_empty() {
18162            self.pull_diagnostics_task = Task::ready(());
18163            return None;
18164        }
18165
18166        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18167            cx.background_executor().timer(debounce).await;
18168
18169            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18170                buffers
18171                    .into_iter()
18172                    .filter_map(|buffer| {
18173                        project
18174                            .update(cx, |project, cx| {
18175                                project.lsp_store().update(cx, |lsp_store, cx| {
18176                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18177                                })
18178                            })
18179                            .ok()
18180                    })
18181                    .collect::<FuturesUnordered<_>>()
18182            }) else {
18183                return;
18184            };
18185
18186            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18187                match pull_task {
18188                    Ok(()) => {
18189                        if editor
18190                            .update_in(cx, |editor, window, cx| {
18191                                editor.update_diagnostics_state(window, cx);
18192                            })
18193                            .is_err()
18194                        {
18195                            return;
18196                        }
18197                    }
18198                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18199                }
18200            }
18201        });
18202
18203        Some(())
18204    }
18205
18206    pub fn set_selections_from_remote(
18207        &mut self,
18208        selections: Vec<Selection<Anchor>>,
18209        pending_selection: Option<Selection<Anchor>>,
18210        window: &mut Window,
18211        cx: &mut Context<Self>,
18212    ) {
18213        let old_cursor_position = self.selections.newest_anchor().head();
18214        self.selections
18215            .change_with(&self.display_snapshot(cx), |s| {
18216                s.select_anchors(selections);
18217                if let Some(pending_selection) = pending_selection {
18218                    s.set_pending(pending_selection, SelectMode::Character);
18219                } else {
18220                    s.clear_pending();
18221                }
18222            });
18223        self.selections_did_change(
18224            false,
18225            &old_cursor_position,
18226            SelectionEffects::default(),
18227            window,
18228            cx,
18229        );
18230    }
18231
18232    pub fn transact(
18233        &mut self,
18234        window: &mut Window,
18235        cx: &mut Context<Self>,
18236        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18237    ) -> Option<TransactionId> {
18238        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18239            this.start_transaction_at(Instant::now(), window, cx);
18240            update(this, window, cx);
18241            this.end_transaction_at(Instant::now(), cx)
18242        })
18243    }
18244
18245    pub fn start_transaction_at(
18246        &mut self,
18247        now: Instant,
18248        window: &mut Window,
18249        cx: &mut Context<Self>,
18250    ) -> Option<TransactionId> {
18251        self.end_selection(window, cx);
18252        if let Some(tx_id) = self
18253            .buffer
18254            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18255        {
18256            self.selection_history
18257                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18258            cx.emit(EditorEvent::TransactionBegun {
18259                transaction_id: tx_id,
18260            });
18261            Some(tx_id)
18262        } else {
18263            None
18264        }
18265    }
18266
18267    pub fn end_transaction_at(
18268        &mut self,
18269        now: Instant,
18270        cx: &mut Context<Self>,
18271    ) -> Option<TransactionId> {
18272        if let Some(transaction_id) = self
18273            .buffer
18274            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18275        {
18276            if let Some((_, end_selections)) =
18277                self.selection_history.transaction_mut(transaction_id)
18278            {
18279                *end_selections = Some(self.selections.disjoint_anchors_arc());
18280            } else {
18281                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18282            }
18283
18284            cx.emit(EditorEvent::Edited { transaction_id });
18285            Some(transaction_id)
18286        } else {
18287            None
18288        }
18289    }
18290
18291    pub fn modify_transaction_selection_history(
18292        &mut self,
18293        transaction_id: TransactionId,
18294        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18295    ) -> bool {
18296        self.selection_history
18297            .transaction_mut(transaction_id)
18298            .map(modify)
18299            .is_some()
18300    }
18301
18302    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18303        if self.selection_mark_mode {
18304            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18305                s.move_with(|_, sel| {
18306                    sel.collapse_to(sel.head(), SelectionGoal::None);
18307                });
18308            })
18309        }
18310        self.selection_mark_mode = true;
18311        cx.notify();
18312    }
18313
18314    pub fn swap_selection_ends(
18315        &mut self,
18316        _: &actions::SwapSelectionEnds,
18317        window: &mut Window,
18318        cx: &mut Context<Self>,
18319    ) {
18320        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18321            s.move_with(|_, sel| {
18322                if sel.start != sel.end {
18323                    sel.reversed = !sel.reversed
18324                }
18325            });
18326        });
18327        self.request_autoscroll(Autoscroll::newest(), cx);
18328        cx.notify();
18329    }
18330
18331    pub fn toggle_focus(
18332        workspace: &mut Workspace,
18333        _: &actions::ToggleFocus,
18334        window: &mut Window,
18335        cx: &mut Context<Workspace>,
18336    ) {
18337        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18338            return;
18339        };
18340        workspace.activate_item(&item, true, true, window, cx);
18341    }
18342
18343    pub fn toggle_fold(
18344        &mut self,
18345        _: &actions::ToggleFold,
18346        window: &mut Window,
18347        cx: &mut Context<Self>,
18348    ) {
18349        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18350            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18351            let selection = self.selections.newest::<Point>(&display_map);
18352
18353            let range = if selection.is_empty() {
18354                let point = selection.head().to_display_point(&display_map);
18355                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18356                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18357                    .to_point(&display_map);
18358                start..end
18359            } else {
18360                selection.range()
18361            };
18362            if display_map.folds_in_range(range).next().is_some() {
18363                self.unfold_lines(&Default::default(), window, cx)
18364            } else {
18365                self.fold(&Default::default(), window, cx)
18366            }
18367        } else {
18368            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18369            let buffer_ids: HashSet<_> = self
18370                .selections
18371                .disjoint_anchor_ranges()
18372                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18373                .collect();
18374
18375            let should_unfold = buffer_ids
18376                .iter()
18377                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18378
18379            for buffer_id in buffer_ids {
18380                if should_unfold {
18381                    self.unfold_buffer(buffer_id, cx);
18382                } else {
18383                    self.fold_buffer(buffer_id, cx);
18384                }
18385            }
18386        }
18387    }
18388
18389    pub fn toggle_fold_recursive(
18390        &mut self,
18391        _: &actions::ToggleFoldRecursive,
18392        window: &mut Window,
18393        cx: &mut Context<Self>,
18394    ) {
18395        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18396
18397        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18398        let range = if selection.is_empty() {
18399            let point = selection.head().to_display_point(&display_map);
18400            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18401            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18402                .to_point(&display_map);
18403            start..end
18404        } else {
18405            selection.range()
18406        };
18407        if display_map.folds_in_range(range).next().is_some() {
18408            self.unfold_recursive(&Default::default(), window, cx)
18409        } else {
18410            self.fold_recursive(&Default::default(), window, cx)
18411        }
18412    }
18413
18414    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18415        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18416            let mut to_fold = Vec::new();
18417            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18418            let selections = self.selections.all_adjusted(&display_map);
18419
18420            for selection in selections {
18421                let range = selection.range().sorted();
18422                let buffer_start_row = range.start.row;
18423
18424                if range.start.row != range.end.row {
18425                    let mut found = false;
18426                    let mut row = range.start.row;
18427                    while row <= range.end.row {
18428                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18429                        {
18430                            found = true;
18431                            row = crease.range().end.row + 1;
18432                            to_fold.push(crease);
18433                        } else {
18434                            row += 1
18435                        }
18436                    }
18437                    if found {
18438                        continue;
18439                    }
18440                }
18441
18442                for row in (0..=range.start.row).rev() {
18443                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18444                        && crease.range().end.row >= buffer_start_row
18445                    {
18446                        to_fold.push(crease);
18447                        if row <= range.start.row {
18448                            break;
18449                        }
18450                    }
18451                }
18452            }
18453
18454            self.fold_creases(to_fold, true, window, cx);
18455        } else {
18456            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18457            let buffer_ids = self
18458                .selections
18459                .disjoint_anchor_ranges()
18460                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18461                .collect::<HashSet<_>>();
18462            for buffer_id in buffer_ids {
18463                self.fold_buffer(buffer_id, cx);
18464            }
18465        }
18466    }
18467
18468    pub fn toggle_fold_all(
18469        &mut self,
18470        _: &actions::ToggleFoldAll,
18471        window: &mut Window,
18472        cx: &mut Context<Self>,
18473    ) {
18474        if self.buffer.read(cx).is_singleton() {
18475            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18476            let has_folds = display_map
18477                .folds_in_range(0..display_map.buffer_snapshot().len())
18478                .next()
18479                .is_some();
18480
18481            if has_folds {
18482                self.unfold_all(&actions::UnfoldAll, window, cx);
18483            } else {
18484                self.fold_all(&actions::FoldAll, window, cx);
18485            }
18486        } else {
18487            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18488            let should_unfold = buffer_ids
18489                .iter()
18490                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18491
18492            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18493                editor
18494                    .update_in(cx, |editor, _, cx| {
18495                        for buffer_id in buffer_ids {
18496                            if should_unfold {
18497                                editor.unfold_buffer(buffer_id, cx);
18498                            } else {
18499                                editor.fold_buffer(buffer_id, cx);
18500                            }
18501                        }
18502                    })
18503                    .ok();
18504            });
18505        }
18506    }
18507
18508    fn fold_at_level(
18509        &mut self,
18510        fold_at: &FoldAtLevel,
18511        window: &mut Window,
18512        cx: &mut Context<Self>,
18513    ) {
18514        if !self.buffer.read(cx).is_singleton() {
18515            return;
18516        }
18517
18518        let fold_at_level = fold_at.0;
18519        let snapshot = self.buffer.read(cx).snapshot(cx);
18520        let mut to_fold = Vec::new();
18521        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18522
18523        let row_ranges_to_keep: Vec<Range<u32>> = self
18524            .selections
18525            .all::<Point>(&self.display_snapshot(cx))
18526            .into_iter()
18527            .map(|sel| sel.start.row..sel.end.row)
18528            .collect();
18529
18530        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18531            while start_row < end_row {
18532                match self
18533                    .snapshot(window, cx)
18534                    .crease_for_buffer_row(MultiBufferRow(start_row))
18535                {
18536                    Some(crease) => {
18537                        let nested_start_row = crease.range().start.row + 1;
18538                        let nested_end_row = crease.range().end.row;
18539
18540                        if current_level < fold_at_level {
18541                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18542                        } else if current_level == fold_at_level {
18543                            // Fold iff there is no selection completely contained within the fold region
18544                            if !row_ranges_to_keep.iter().any(|selection| {
18545                                selection.end >= nested_start_row
18546                                    && selection.start <= nested_end_row
18547                            }) {
18548                                to_fold.push(crease);
18549                            }
18550                        }
18551
18552                        start_row = nested_end_row + 1;
18553                    }
18554                    None => start_row += 1,
18555                }
18556            }
18557        }
18558
18559        self.fold_creases(to_fold, true, window, cx);
18560    }
18561
18562    pub fn fold_at_level_1(
18563        &mut self,
18564        _: &actions::FoldAtLevel1,
18565        window: &mut Window,
18566        cx: &mut Context<Self>,
18567    ) {
18568        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18569    }
18570
18571    pub fn fold_at_level_2(
18572        &mut self,
18573        _: &actions::FoldAtLevel2,
18574        window: &mut Window,
18575        cx: &mut Context<Self>,
18576    ) {
18577        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18578    }
18579
18580    pub fn fold_at_level_3(
18581        &mut self,
18582        _: &actions::FoldAtLevel3,
18583        window: &mut Window,
18584        cx: &mut Context<Self>,
18585    ) {
18586        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18587    }
18588
18589    pub fn fold_at_level_4(
18590        &mut self,
18591        _: &actions::FoldAtLevel4,
18592        window: &mut Window,
18593        cx: &mut Context<Self>,
18594    ) {
18595        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18596    }
18597
18598    pub fn fold_at_level_5(
18599        &mut self,
18600        _: &actions::FoldAtLevel5,
18601        window: &mut Window,
18602        cx: &mut Context<Self>,
18603    ) {
18604        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18605    }
18606
18607    pub fn fold_at_level_6(
18608        &mut self,
18609        _: &actions::FoldAtLevel6,
18610        window: &mut Window,
18611        cx: &mut Context<Self>,
18612    ) {
18613        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18614    }
18615
18616    pub fn fold_at_level_7(
18617        &mut self,
18618        _: &actions::FoldAtLevel7,
18619        window: &mut Window,
18620        cx: &mut Context<Self>,
18621    ) {
18622        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18623    }
18624
18625    pub fn fold_at_level_8(
18626        &mut self,
18627        _: &actions::FoldAtLevel8,
18628        window: &mut Window,
18629        cx: &mut Context<Self>,
18630    ) {
18631        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18632    }
18633
18634    pub fn fold_at_level_9(
18635        &mut self,
18636        _: &actions::FoldAtLevel9,
18637        window: &mut Window,
18638        cx: &mut Context<Self>,
18639    ) {
18640        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18641    }
18642
18643    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18644        if self.buffer.read(cx).is_singleton() {
18645            let mut fold_ranges = Vec::new();
18646            let snapshot = self.buffer.read(cx).snapshot(cx);
18647
18648            for row in 0..snapshot.max_row().0 {
18649                if let Some(foldable_range) = self
18650                    .snapshot(window, cx)
18651                    .crease_for_buffer_row(MultiBufferRow(row))
18652                {
18653                    fold_ranges.push(foldable_range);
18654                }
18655            }
18656
18657            self.fold_creases(fold_ranges, true, window, cx);
18658        } else {
18659            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18660                editor
18661                    .update_in(cx, |editor, _, cx| {
18662                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18663                            editor.fold_buffer(buffer_id, cx);
18664                        }
18665                    })
18666                    .ok();
18667            });
18668        }
18669    }
18670
18671    pub fn fold_function_bodies(
18672        &mut self,
18673        _: &actions::FoldFunctionBodies,
18674        window: &mut Window,
18675        cx: &mut Context<Self>,
18676    ) {
18677        let snapshot = self.buffer.read(cx).snapshot(cx);
18678
18679        let ranges = snapshot
18680            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18681            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18682            .collect::<Vec<_>>();
18683
18684        let creases = ranges
18685            .into_iter()
18686            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18687            .collect();
18688
18689        self.fold_creases(creases, true, window, cx);
18690    }
18691
18692    pub fn fold_recursive(
18693        &mut self,
18694        _: &actions::FoldRecursive,
18695        window: &mut Window,
18696        cx: &mut Context<Self>,
18697    ) {
18698        let mut to_fold = Vec::new();
18699        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18700        let selections = self.selections.all_adjusted(&display_map);
18701
18702        for selection in selections {
18703            let range = selection.range().sorted();
18704            let buffer_start_row = range.start.row;
18705
18706            if range.start.row != range.end.row {
18707                let mut found = false;
18708                for row in range.start.row..=range.end.row {
18709                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18710                        found = true;
18711                        to_fold.push(crease);
18712                    }
18713                }
18714                if found {
18715                    continue;
18716                }
18717            }
18718
18719            for row in (0..=range.start.row).rev() {
18720                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18721                    if crease.range().end.row >= buffer_start_row {
18722                        to_fold.push(crease);
18723                    } else {
18724                        break;
18725                    }
18726                }
18727            }
18728        }
18729
18730        self.fold_creases(to_fold, true, window, cx);
18731    }
18732
18733    pub fn fold_at(
18734        &mut self,
18735        buffer_row: MultiBufferRow,
18736        window: &mut Window,
18737        cx: &mut Context<Self>,
18738    ) {
18739        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18740
18741        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18742            let autoscroll = self
18743                .selections
18744                .all::<Point>(&display_map)
18745                .iter()
18746                .any(|selection| crease.range().overlaps(&selection.range()));
18747
18748            self.fold_creases(vec![crease], autoscroll, window, cx);
18749        }
18750    }
18751
18752    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18753        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18754            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18755            let buffer = display_map.buffer_snapshot();
18756            let selections = self.selections.all::<Point>(&display_map);
18757            let ranges = selections
18758                .iter()
18759                .map(|s| {
18760                    let range = s.display_range(&display_map).sorted();
18761                    let mut start = range.start.to_point(&display_map);
18762                    let mut end = range.end.to_point(&display_map);
18763                    start.column = 0;
18764                    end.column = buffer.line_len(MultiBufferRow(end.row));
18765                    start..end
18766                })
18767                .collect::<Vec<_>>();
18768
18769            self.unfold_ranges(&ranges, true, true, cx);
18770        } else {
18771            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18772            let buffer_ids = self
18773                .selections
18774                .disjoint_anchor_ranges()
18775                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18776                .collect::<HashSet<_>>();
18777            for buffer_id in buffer_ids {
18778                self.unfold_buffer(buffer_id, cx);
18779            }
18780        }
18781    }
18782
18783    pub fn unfold_recursive(
18784        &mut self,
18785        _: &UnfoldRecursive,
18786        _window: &mut Window,
18787        cx: &mut Context<Self>,
18788    ) {
18789        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18790        let selections = self.selections.all::<Point>(&display_map);
18791        let ranges = selections
18792            .iter()
18793            .map(|s| {
18794                let mut range = s.display_range(&display_map).sorted();
18795                *range.start.column_mut() = 0;
18796                *range.end.column_mut() = display_map.line_len(range.end.row());
18797                let start = range.start.to_point(&display_map);
18798                let end = range.end.to_point(&display_map);
18799                start..end
18800            })
18801            .collect::<Vec<_>>();
18802
18803        self.unfold_ranges(&ranges, true, true, cx);
18804    }
18805
18806    pub fn unfold_at(
18807        &mut self,
18808        buffer_row: MultiBufferRow,
18809        _window: &mut Window,
18810        cx: &mut Context<Self>,
18811    ) {
18812        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18813
18814        let intersection_range = Point::new(buffer_row.0, 0)
18815            ..Point::new(
18816                buffer_row.0,
18817                display_map.buffer_snapshot().line_len(buffer_row),
18818            );
18819
18820        let autoscroll = self
18821            .selections
18822            .all::<Point>(&display_map)
18823            .iter()
18824            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18825
18826        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18827    }
18828
18829    pub fn unfold_all(
18830        &mut self,
18831        _: &actions::UnfoldAll,
18832        _window: &mut Window,
18833        cx: &mut Context<Self>,
18834    ) {
18835        if self.buffer.read(cx).is_singleton() {
18836            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18837            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18838        } else {
18839            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18840                editor
18841                    .update(cx, |editor, cx| {
18842                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18843                            editor.unfold_buffer(buffer_id, cx);
18844                        }
18845                    })
18846                    .ok();
18847            });
18848        }
18849    }
18850
18851    pub fn fold_selected_ranges(
18852        &mut self,
18853        _: &FoldSelectedRanges,
18854        window: &mut Window,
18855        cx: &mut Context<Self>,
18856    ) {
18857        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18858        let selections = self.selections.all_adjusted(&display_map);
18859        let ranges = selections
18860            .into_iter()
18861            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18862            .collect::<Vec<_>>();
18863        self.fold_creases(ranges, true, window, cx);
18864    }
18865
18866    pub fn fold_ranges<T: ToOffset + Clone>(
18867        &mut self,
18868        ranges: Vec<Range<T>>,
18869        auto_scroll: bool,
18870        window: &mut Window,
18871        cx: &mut Context<Self>,
18872    ) {
18873        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18874        let ranges = ranges
18875            .into_iter()
18876            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18877            .collect::<Vec<_>>();
18878        self.fold_creases(ranges, auto_scroll, window, cx);
18879    }
18880
18881    pub fn fold_creases<T: ToOffset + Clone>(
18882        &mut self,
18883        creases: Vec<Crease<T>>,
18884        auto_scroll: bool,
18885        _window: &mut Window,
18886        cx: &mut Context<Self>,
18887    ) {
18888        if creases.is_empty() {
18889            return;
18890        }
18891
18892        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18893
18894        if auto_scroll {
18895            self.request_autoscroll(Autoscroll::fit(), cx);
18896        }
18897
18898        cx.notify();
18899
18900        self.scrollbar_marker_state.dirty = true;
18901        self.folds_did_change(cx);
18902    }
18903
18904    /// Removes any folds whose ranges intersect any of the given ranges.
18905    pub fn unfold_ranges<T: ToOffset + Clone>(
18906        &mut self,
18907        ranges: &[Range<T>],
18908        inclusive: bool,
18909        auto_scroll: bool,
18910        cx: &mut Context<Self>,
18911    ) {
18912        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18913            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18914        });
18915        self.folds_did_change(cx);
18916    }
18917
18918    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18919        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18920            return;
18921        }
18922
18923        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18924        self.display_map.update(cx, |display_map, cx| {
18925            display_map.fold_buffers([buffer_id], cx)
18926        });
18927
18928        let snapshot = self.display_snapshot(cx);
18929        self.selections.change_with(&snapshot, |selections| {
18930            selections.remove_selections_from_buffer(buffer_id);
18931        });
18932
18933        cx.emit(EditorEvent::BufferFoldToggled {
18934            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18935            folded: true,
18936        });
18937        cx.notify();
18938    }
18939
18940    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18941        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18942            return;
18943        }
18944        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18945        self.display_map.update(cx, |display_map, cx| {
18946            display_map.unfold_buffers([buffer_id], cx);
18947        });
18948        cx.emit(EditorEvent::BufferFoldToggled {
18949            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18950            folded: false,
18951        });
18952        cx.notify();
18953    }
18954
18955    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18956        self.display_map.read(cx).is_buffer_folded(buffer)
18957    }
18958
18959    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18960        self.display_map.read(cx).folded_buffers()
18961    }
18962
18963    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18964        self.display_map.update(cx, |display_map, cx| {
18965            display_map.disable_header_for_buffer(buffer_id, cx);
18966        });
18967        cx.notify();
18968    }
18969
18970    /// Removes any folds with the given ranges.
18971    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18972        &mut self,
18973        ranges: &[Range<T>],
18974        type_id: TypeId,
18975        auto_scroll: bool,
18976        cx: &mut Context<Self>,
18977    ) {
18978        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18979            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18980        });
18981        self.folds_did_change(cx);
18982    }
18983
18984    fn remove_folds_with<T: ToOffset + Clone>(
18985        &mut self,
18986        ranges: &[Range<T>],
18987        auto_scroll: bool,
18988        cx: &mut Context<Self>,
18989        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18990    ) {
18991        if ranges.is_empty() {
18992            return;
18993        }
18994
18995        let mut buffers_affected = HashSet::default();
18996        let multi_buffer = self.buffer().read(cx);
18997        for range in ranges {
18998            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18999                buffers_affected.insert(buffer.read(cx).remote_id());
19000            };
19001        }
19002
19003        self.display_map.update(cx, update);
19004
19005        if auto_scroll {
19006            self.request_autoscroll(Autoscroll::fit(), cx);
19007        }
19008
19009        cx.notify();
19010        self.scrollbar_marker_state.dirty = true;
19011        self.active_indent_guides_state.dirty = true;
19012    }
19013
19014    pub fn update_renderer_widths(
19015        &mut self,
19016        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19017        cx: &mut Context<Self>,
19018    ) -> bool {
19019        self.display_map
19020            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19021    }
19022
19023    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19024        self.display_map.read(cx).fold_placeholder.clone()
19025    }
19026
19027    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19028        self.buffer.update(cx, |buffer, cx| {
19029            buffer.set_all_diff_hunks_expanded(cx);
19030        });
19031    }
19032
19033    pub fn expand_all_diff_hunks(
19034        &mut self,
19035        _: &ExpandAllDiffHunks,
19036        _window: &mut Window,
19037        cx: &mut Context<Self>,
19038    ) {
19039        self.buffer.update(cx, |buffer, cx| {
19040            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19041        });
19042    }
19043
19044    pub fn collapse_all_diff_hunks(
19045        &mut self,
19046        _: &CollapseAllDiffHunks,
19047        _window: &mut Window,
19048        cx: &mut Context<Self>,
19049    ) {
19050        self.buffer.update(cx, |buffer, cx| {
19051            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19052        });
19053    }
19054
19055    pub fn toggle_selected_diff_hunks(
19056        &mut self,
19057        _: &ToggleSelectedDiffHunks,
19058        _window: &mut Window,
19059        cx: &mut Context<Self>,
19060    ) {
19061        let ranges: Vec<_> = self
19062            .selections
19063            .disjoint_anchors()
19064            .iter()
19065            .map(|s| s.range())
19066            .collect();
19067        self.toggle_diff_hunks_in_ranges(ranges, cx);
19068    }
19069
19070    pub fn diff_hunks_in_ranges<'a>(
19071        &'a self,
19072        ranges: &'a [Range<Anchor>],
19073        buffer: &'a MultiBufferSnapshot,
19074    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19075        ranges.iter().flat_map(move |range| {
19076            let end_excerpt_id = range.end.excerpt_id;
19077            let range = range.to_point(buffer);
19078            let mut peek_end = range.end;
19079            if range.end.row < buffer.max_row().0 {
19080                peek_end = Point::new(range.end.row + 1, 0);
19081            }
19082            buffer
19083                .diff_hunks_in_range(range.start..peek_end)
19084                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19085        })
19086    }
19087
19088    pub fn has_stageable_diff_hunks_in_ranges(
19089        &self,
19090        ranges: &[Range<Anchor>],
19091        snapshot: &MultiBufferSnapshot,
19092    ) -> bool {
19093        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19094        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19095    }
19096
19097    pub fn toggle_staged_selected_diff_hunks(
19098        &mut self,
19099        _: &::git::ToggleStaged,
19100        _: &mut Window,
19101        cx: &mut Context<Self>,
19102    ) {
19103        let snapshot = self.buffer.read(cx).snapshot(cx);
19104        let ranges: Vec<_> = self
19105            .selections
19106            .disjoint_anchors()
19107            .iter()
19108            .map(|s| s.range())
19109            .collect();
19110        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19111        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19112    }
19113
19114    pub fn set_render_diff_hunk_controls(
19115        &mut self,
19116        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19117        cx: &mut Context<Self>,
19118    ) {
19119        self.render_diff_hunk_controls = render_diff_hunk_controls;
19120        cx.notify();
19121    }
19122
19123    pub fn stage_and_next(
19124        &mut self,
19125        _: &::git::StageAndNext,
19126        window: &mut Window,
19127        cx: &mut Context<Self>,
19128    ) {
19129        self.do_stage_or_unstage_and_next(true, window, cx);
19130    }
19131
19132    pub fn unstage_and_next(
19133        &mut self,
19134        _: &::git::UnstageAndNext,
19135        window: &mut Window,
19136        cx: &mut Context<Self>,
19137    ) {
19138        self.do_stage_or_unstage_and_next(false, window, cx);
19139    }
19140
19141    pub fn stage_or_unstage_diff_hunks(
19142        &mut self,
19143        stage: bool,
19144        ranges: Vec<Range<Anchor>>,
19145        cx: &mut Context<Self>,
19146    ) {
19147        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19148        cx.spawn(async move |this, cx| {
19149            task.await?;
19150            this.update(cx, |this, cx| {
19151                let snapshot = this.buffer.read(cx).snapshot(cx);
19152                let chunk_by = this
19153                    .diff_hunks_in_ranges(&ranges, &snapshot)
19154                    .chunk_by(|hunk| hunk.buffer_id);
19155                for (buffer_id, hunks) in &chunk_by {
19156                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19157                }
19158            })
19159        })
19160        .detach_and_log_err(cx);
19161    }
19162
19163    fn save_buffers_for_ranges_if_needed(
19164        &mut self,
19165        ranges: &[Range<Anchor>],
19166        cx: &mut Context<Editor>,
19167    ) -> Task<Result<()>> {
19168        let multibuffer = self.buffer.read(cx);
19169        let snapshot = multibuffer.read(cx);
19170        let buffer_ids: HashSet<_> = ranges
19171            .iter()
19172            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19173            .collect();
19174        drop(snapshot);
19175
19176        let mut buffers = HashSet::default();
19177        for buffer_id in buffer_ids {
19178            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19179                let buffer = buffer_entity.read(cx);
19180                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19181                {
19182                    buffers.insert(buffer_entity);
19183                }
19184            }
19185        }
19186
19187        if let Some(project) = &self.project {
19188            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19189        } else {
19190            Task::ready(Ok(()))
19191        }
19192    }
19193
19194    fn do_stage_or_unstage_and_next(
19195        &mut self,
19196        stage: bool,
19197        window: &mut Window,
19198        cx: &mut Context<Self>,
19199    ) {
19200        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19201
19202        if ranges.iter().any(|range| range.start != range.end) {
19203            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19204            return;
19205        }
19206
19207        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19208        let snapshot = self.snapshot(window, cx);
19209        let position = self
19210            .selections
19211            .newest::<Point>(&snapshot.display_snapshot)
19212            .head();
19213        let mut row = snapshot
19214            .buffer_snapshot()
19215            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19216            .find(|hunk| hunk.row_range.start.0 > position.row)
19217            .map(|hunk| hunk.row_range.start);
19218
19219        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19220        // Outside of the project diff editor, wrap around to the beginning.
19221        if !all_diff_hunks_expanded {
19222            row = row.or_else(|| {
19223                snapshot
19224                    .buffer_snapshot()
19225                    .diff_hunks_in_range(Point::zero()..position)
19226                    .find(|hunk| hunk.row_range.end.0 < position.row)
19227                    .map(|hunk| hunk.row_range.start)
19228            });
19229        }
19230
19231        if let Some(row) = row {
19232            let destination = Point::new(row.0, 0);
19233            let autoscroll = Autoscroll::center();
19234
19235            self.unfold_ranges(&[destination..destination], false, false, cx);
19236            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19237                s.select_ranges([destination..destination]);
19238            });
19239        }
19240    }
19241
19242    fn do_stage_or_unstage(
19243        &self,
19244        stage: bool,
19245        buffer_id: BufferId,
19246        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19247        cx: &mut App,
19248    ) -> Option<()> {
19249        let project = self.project()?;
19250        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19251        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19252        let buffer_snapshot = buffer.read(cx).snapshot();
19253        let file_exists = buffer_snapshot
19254            .file()
19255            .is_some_and(|file| file.disk_state().exists());
19256        diff.update(cx, |diff, cx| {
19257            diff.stage_or_unstage_hunks(
19258                stage,
19259                &hunks
19260                    .map(|hunk| buffer_diff::DiffHunk {
19261                        buffer_range: hunk.buffer_range,
19262                        diff_base_byte_range: hunk.diff_base_byte_range,
19263                        secondary_status: hunk.secondary_status,
19264                        range: Point::zero()..Point::zero(), // unused
19265                    })
19266                    .collect::<Vec<_>>(),
19267                &buffer_snapshot,
19268                file_exists,
19269                cx,
19270            )
19271        });
19272        None
19273    }
19274
19275    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19276        let ranges: Vec<_> = self
19277            .selections
19278            .disjoint_anchors()
19279            .iter()
19280            .map(|s| s.range())
19281            .collect();
19282        self.buffer
19283            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19284    }
19285
19286    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19287        self.buffer.update(cx, |buffer, cx| {
19288            let ranges = vec![Anchor::min()..Anchor::max()];
19289            if !buffer.all_diff_hunks_expanded()
19290                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19291            {
19292                buffer.collapse_diff_hunks(ranges, cx);
19293                true
19294            } else {
19295                false
19296            }
19297        })
19298    }
19299
19300    fn toggle_diff_hunks_in_ranges(
19301        &mut self,
19302        ranges: Vec<Range<Anchor>>,
19303        cx: &mut Context<Editor>,
19304    ) {
19305        self.buffer.update(cx, |buffer, cx| {
19306            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19307            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19308        })
19309    }
19310
19311    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19312        self.buffer.update(cx, |buffer, cx| {
19313            let snapshot = buffer.snapshot(cx);
19314            let excerpt_id = range.end.excerpt_id;
19315            let point_range = range.to_point(&snapshot);
19316            let expand = !buffer.single_hunk_is_expanded(range, cx);
19317            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19318        })
19319    }
19320
19321    pub(crate) fn apply_all_diff_hunks(
19322        &mut self,
19323        _: &ApplyAllDiffHunks,
19324        window: &mut Window,
19325        cx: &mut Context<Self>,
19326    ) {
19327        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19328
19329        let buffers = self.buffer.read(cx).all_buffers();
19330        for branch_buffer in buffers {
19331            branch_buffer.update(cx, |branch_buffer, cx| {
19332                branch_buffer.merge_into_base(Vec::new(), cx);
19333            });
19334        }
19335
19336        if let Some(project) = self.project.clone() {
19337            self.save(
19338                SaveOptions {
19339                    format: true,
19340                    autosave: false,
19341                },
19342                project,
19343                window,
19344                cx,
19345            )
19346            .detach_and_log_err(cx);
19347        }
19348    }
19349
19350    pub(crate) fn apply_selected_diff_hunks(
19351        &mut self,
19352        _: &ApplyDiffHunk,
19353        window: &mut Window,
19354        cx: &mut Context<Self>,
19355    ) {
19356        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19357        let snapshot = self.snapshot(window, cx);
19358        let hunks = snapshot.hunks_for_ranges(
19359            self.selections
19360                .all(&snapshot.display_snapshot)
19361                .into_iter()
19362                .map(|selection| selection.range()),
19363        );
19364        let mut ranges_by_buffer = HashMap::default();
19365        self.transact(window, cx, |editor, _window, cx| {
19366            for hunk in hunks {
19367                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19368                    ranges_by_buffer
19369                        .entry(buffer.clone())
19370                        .or_insert_with(Vec::new)
19371                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19372                }
19373            }
19374
19375            for (buffer, ranges) in ranges_by_buffer {
19376                buffer.update(cx, |buffer, cx| {
19377                    buffer.merge_into_base(ranges, cx);
19378                });
19379            }
19380        });
19381
19382        if let Some(project) = self.project.clone() {
19383            self.save(
19384                SaveOptions {
19385                    format: true,
19386                    autosave: false,
19387                },
19388                project,
19389                window,
19390                cx,
19391            )
19392            .detach_and_log_err(cx);
19393        }
19394    }
19395
19396    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19397        if hovered != self.gutter_hovered {
19398            self.gutter_hovered = hovered;
19399            cx.notify();
19400        }
19401    }
19402
19403    pub fn insert_blocks(
19404        &mut self,
19405        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19406        autoscroll: Option<Autoscroll>,
19407        cx: &mut Context<Self>,
19408    ) -> Vec<CustomBlockId> {
19409        let blocks = self
19410            .display_map
19411            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19412        if let Some(autoscroll) = autoscroll {
19413            self.request_autoscroll(autoscroll, cx);
19414        }
19415        cx.notify();
19416        blocks
19417    }
19418
19419    pub fn resize_blocks(
19420        &mut self,
19421        heights: HashMap<CustomBlockId, u32>,
19422        autoscroll: Option<Autoscroll>,
19423        cx: &mut Context<Self>,
19424    ) {
19425        self.display_map
19426            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19427        if let Some(autoscroll) = autoscroll {
19428            self.request_autoscroll(autoscroll, cx);
19429        }
19430        cx.notify();
19431    }
19432
19433    pub fn replace_blocks(
19434        &mut self,
19435        renderers: HashMap<CustomBlockId, RenderBlock>,
19436        autoscroll: Option<Autoscroll>,
19437        cx: &mut Context<Self>,
19438    ) {
19439        self.display_map
19440            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19441        if let Some(autoscroll) = autoscroll {
19442            self.request_autoscroll(autoscroll, cx);
19443        }
19444        cx.notify();
19445    }
19446
19447    pub fn remove_blocks(
19448        &mut self,
19449        block_ids: HashSet<CustomBlockId>,
19450        autoscroll: Option<Autoscroll>,
19451        cx: &mut Context<Self>,
19452    ) {
19453        self.display_map.update(cx, |display_map, cx| {
19454            display_map.remove_blocks(block_ids, cx)
19455        });
19456        if let Some(autoscroll) = autoscroll {
19457            self.request_autoscroll(autoscroll, cx);
19458        }
19459        cx.notify();
19460    }
19461
19462    pub fn row_for_block(
19463        &self,
19464        block_id: CustomBlockId,
19465        cx: &mut Context<Self>,
19466    ) -> Option<DisplayRow> {
19467        self.display_map
19468            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19469    }
19470
19471    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19472        self.focused_block = Some(focused_block);
19473    }
19474
19475    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19476        self.focused_block.take()
19477    }
19478
19479    pub fn insert_creases(
19480        &mut self,
19481        creases: impl IntoIterator<Item = Crease<Anchor>>,
19482        cx: &mut Context<Self>,
19483    ) -> Vec<CreaseId> {
19484        self.display_map
19485            .update(cx, |map, cx| map.insert_creases(creases, cx))
19486    }
19487
19488    pub fn remove_creases(
19489        &mut self,
19490        ids: impl IntoIterator<Item = CreaseId>,
19491        cx: &mut Context<Self>,
19492    ) -> Vec<(CreaseId, Range<Anchor>)> {
19493        self.display_map
19494            .update(cx, |map, cx| map.remove_creases(ids, cx))
19495    }
19496
19497    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19498        self.display_map
19499            .update(cx, |map, cx| map.snapshot(cx))
19500            .longest_row()
19501    }
19502
19503    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19504        self.display_map
19505            .update(cx, |map, cx| map.snapshot(cx))
19506            .max_point()
19507    }
19508
19509    pub fn text(&self, cx: &App) -> String {
19510        self.buffer.read(cx).read(cx).text()
19511    }
19512
19513    pub fn is_empty(&self, cx: &App) -> bool {
19514        self.buffer.read(cx).read(cx).is_empty()
19515    }
19516
19517    pub fn text_option(&self, cx: &App) -> Option<String> {
19518        let text = self.text(cx);
19519        let text = text.trim();
19520
19521        if text.is_empty() {
19522            return None;
19523        }
19524
19525        Some(text.to_string())
19526    }
19527
19528    pub fn set_text(
19529        &mut self,
19530        text: impl Into<Arc<str>>,
19531        window: &mut Window,
19532        cx: &mut Context<Self>,
19533    ) {
19534        self.transact(window, cx, |this, _, cx| {
19535            this.buffer
19536                .read(cx)
19537                .as_singleton()
19538                .expect("you can only call set_text on editors for singleton buffers")
19539                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19540        });
19541    }
19542
19543    pub fn display_text(&self, cx: &mut App) -> String {
19544        self.display_map
19545            .update(cx, |map, cx| map.snapshot(cx))
19546            .text()
19547    }
19548
19549    fn create_minimap(
19550        &self,
19551        minimap_settings: MinimapSettings,
19552        window: &mut Window,
19553        cx: &mut Context<Self>,
19554    ) -> Option<Entity<Self>> {
19555        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19556            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19557    }
19558
19559    fn initialize_new_minimap(
19560        &self,
19561        minimap_settings: MinimapSettings,
19562        window: &mut Window,
19563        cx: &mut Context<Self>,
19564    ) -> Entity<Self> {
19565        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19566
19567        let mut minimap = Editor::new_internal(
19568            EditorMode::Minimap {
19569                parent: cx.weak_entity(),
19570            },
19571            self.buffer.clone(),
19572            None,
19573            Some(self.display_map.clone()),
19574            window,
19575            cx,
19576        );
19577        minimap.scroll_manager.clone_state(&self.scroll_manager);
19578        minimap.set_text_style_refinement(TextStyleRefinement {
19579            font_size: Some(MINIMAP_FONT_SIZE),
19580            font_weight: Some(MINIMAP_FONT_WEIGHT),
19581            ..Default::default()
19582        });
19583        minimap.update_minimap_configuration(minimap_settings, cx);
19584        cx.new(|_| minimap)
19585    }
19586
19587    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19588        let current_line_highlight = minimap_settings
19589            .current_line_highlight
19590            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19591        self.set_current_line_highlight(Some(current_line_highlight));
19592    }
19593
19594    pub fn minimap(&self) -> Option<&Entity<Self>> {
19595        self.minimap
19596            .as_ref()
19597            .filter(|_| self.minimap_visibility.visible())
19598    }
19599
19600    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19601        let mut wrap_guides = smallvec![];
19602
19603        if self.show_wrap_guides == Some(false) {
19604            return wrap_guides;
19605        }
19606
19607        let settings = self.buffer.read(cx).language_settings(cx);
19608        if settings.show_wrap_guides {
19609            match self.soft_wrap_mode(cx) {
19610                SoftWrap::Column(soft_wrap) => {
19611                    wrap_guides.push((soft_wrap as usize, true));
19612                }
19613                SoftWrap::Bounded(soft_wrap) => {
19614                    wrap_guides.push((soft_wrap as usize, true));
19615                }
19616                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19617            }
19618            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19619        }
19620
19621        wrap_guides
19622    }
19623
19624    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19625        let settings = self.buffer.read(cx).language_settings(cx);
19626        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19627        match mode {
19628            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19629                SoftWrap::None
19630            }
19631            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19632            language_settings::SoftWrap::PreferredLineLength => {
19633                SoftWrap::Column(settings.preferred_line_length)
19634            }
19635            language_settings::SoftWrap::Bounded => {
19636                SoftWrap::Bounded(settings.preferred_line_length)
19637            }
19638        }
19639    }
19640
19641    pub fn set_soft_wrap_mode(
19642        &mut self,
19643        mode: language_settings::SoftWrap,
19644
19645        cx: &mut Context<Self>,
19646    ) {
19647        self.soft_wrap_mode_override = Some(mode);
19648        cx.notify();
19649    }
19650
19651    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19652        self.hard_wrap = hard_wrap;
19653        cx.notify();
19654    }
19655
19656    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19657        self.text_style_refinement = Some(style);
19658    }
19659
19660    /// called by the Element so we know what style we were most recently rendered with.
19661    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19662        // We intentionally do not inform the display map about the minimap style
19663        // so that wrapping is not recalculated and stays consistent for the editor
19664        // and its linked minimap.
19665        if !self.mode.is_minimap() {
19666            let font = style.text.font();
19667            let font_size = style.text.font_size.to_pixels(window.rem_size());
19668            let display_map = self
19669                .placeholder_display_map
19670                .as_ref()
19671                .filter(|_| self.is_empty(cx))
19672                .unwrap_or(&self.display_map);
19673
19674            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19675        }
19676        self.style = Some(style);
19677    }
19678
19679    pub fn style(&self) -> Option<&EditorStyle> {
19680        self.style.as_ref()
19681    }
19682
19683    // Called by the element. This method is not designed to be called outside of the editor
19684    // element's layout code because it does not notify when rewrapping is computed synchronously.
19685    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19686        if self.is_empty(cx) {
19687            self.placeholder_display_map
19688                .as_ref()
19689                .map_or(false, |display_map| {
19690                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19691                })
19692        } else {
19693            self.display_map
19694                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19695        }
19696    }
19697
19698    pub fn set_soft_wrap(&mut self) {
19699        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19700    }
19701
19702    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19703        if self.soft_wrap_mode_override.is_some() {
19704            self.soft_wrap_mode_override.take();
19705        } else {
19706            let soft_wrap = match self.soft_wrap_mode(cx) {
19707                SoftWrap::GitDiff => return,
19708                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19709                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19710                    language_settings::SoftWrap::None
19711                }
19712            };
19713            self.soft_wrap_mode_override = Some(soft_wrap);
19714        }
19715        cx.notify();
19716    }
19717
19718    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19719        let Some(workspace) = self.workspace() else {
19720            return;
19721        };
19722        let fs = workspace.read(cx).app_state().fs.clone();
19723        let current_show = TabBarSettings::get_global(cx).show;
19724        update_settings_file(fs, cx, move |setting, _| {
19725            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19726        });
19727    }
19728
19729    pub fn toggle_indent_guides(
19730        &mut self,
19731        _: &ToggleIndentGuides,
19732        _: &mut Window,
19733        cx: &mut Context<Self>,
19734    ) {
19735        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19736            self.buffer
19737                .read(cx)
19738                .language_settings(cx)
19739                .indent_guides
19740                .enabled
19741        });
19742        self.show_indent_guides = Some(!currently_enabled);
19743        cx.notify();
19744    }
19745
19746    fn should_show_indent_guides(&self) -> Option<bool> {
19747        self.show_indent_guides
19748    }
19749
19750    pub fn toggle_line_numbers(
19751        &mut self,
19752        _: &ToggleLineNumbers,
19753        _: &mut Window,
19754        cx: &mut Context<Self>,
19755    ) {
19756        let mut editor_settings = EditorSettings::get_global(cx).clone();
19757        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19758        EditorSettings::override_global(editor_settings, cx);
19759    }
19760
19761    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19762        if let Some(show_line_numbers) = self.show_line_numbers {
19763            return show_line_numbers;
19764        }
19765        EditorSettings::get_global(cx).gutter.line_numbers
19766    }
19767
19768    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19769        match (
19770            self.use_relative_line_numbers,
19771            EditorSettings::get_global(cx).relative_line_numbers,
19772        ) {
19773            (None, setting) => setting,
19774            (Some(false), _) => RelativeLineNumbers::Disabled,
19775            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19776            (Some(true), _) => RelativeLineNumbers::Enabled,
19777        }
19778    }
19779
19780    pub fn toggle_relative_line_numbers(
19781        &mut self,
19782        _: &ToggleRelativeLineNumbers,
19783        _: &mut Window,
19784        cx: &mut Context<Self>,
19785    ) {
19786        let is_relative = self.relative_line_numbers(cx);
19787        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19788    }
19789
19790    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19791        self.use_relative_line_numbers = is_relative;
19792        cx.notify();
19793    }
19794
19795    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19796        self.show_gutter = show_gutter;
19797        cx.notify();
19798    }
19799
19800    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19801        self.show_scrollbars = ScrollbarAxes {
19802            horizontal: show,
19803            vertical: show,
19804        };
19805        cx.notify();
19806    }
19807
19808    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19809        self.show_scrollbars.vertical = show;
19810        cx.notify();
19811    }
19812
19813    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19814        self.show_scrollbars.horizontal = show;
19815        cx.notify();
19816    }
19817
19818    pub fn set_minimap_visibility(
19819        &mut self,
19820        minimap_visibility: MinimapVisibility,
19821        window: &mut Window,
19822        cx: &mut Context<Self>,
19823    ) {
19824        if self.minimap_visibility != minimap_visibility {
19825            if minimap_visibility.visible() && self.minimap.is_none() {
19826                let minimap_settings = EditorSettings::get_global(cx).minimap;
19827                self.minimap =
19828                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19829            }
19830            self.minimap_visibility = minimap_visibility;
19831            cx.notify();
19832        }
19833    }
19834
19835    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19836        self.set_show_scrollbars(false, cx);
19837        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19838    }
19839
19840    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19841        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19842    }
19843
19844    /// Normally the text in full mode and auto height editors is padded on the
19845    /// left side by roughly half a character width for improved hit testing.
19846    ///
19847    /// Use this method to disable this for cases where this is not wanted (e.g.
19848    /// if you want to align the editor text with some other text above or below)
19849    /// or if you want to add this padding to single-line editors.
19850    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19851        self.offset_content = offset_content;
19852        cx.notify();
19853    }
19854
19855    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19856        self.show_line_numbers = Some(show_line_numbers);
19857        cx.notify();
19858    }
19859
19860    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19861        self.disable_expand_excerpt_buttons = true;
19862        cx.notify();
19863    }
19864
19865    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19866        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19867        cx.notify();
19868    }
19869
19870    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19871        self.show_code_actions = Some(show_code_actions);
19872        cx.notify();
19873    }
19874
19875    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19876        self.show_runnables = Some(show_runnables);
19877        cx.notify();
19878    }
19879
19880    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19881        self.show_breakpoints = Some(show_breakpoints);
19882        cx.notify();
19883    }
19884
19885    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19886        if self.display_map.read(cx).masked != masked {
19887            self.display_map.update(cx, |map, _| map.masked = masked);
19888        }
19889        cx.notify()
19890    }
19891
19892    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19893        self.show_wrap_guides = Some(show_wrap_guides);
19894        cx.notify();
19895    }
19896
19897    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19898        self.show_indent_guides = Some(show_indent_guides);
19899        cx.notify();
19900    }
19901
19902    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19903        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19904            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19905                && let Some(dir) = file.abs_path(cx).parent()
19906            {
19907                return Some(dir.to_owned());
19908            }
19909        }
19910
19911        None
19912    }
19913
19914    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19915        self.active_excerpt(cx)?
19916            .1
19917            .read(cx)
19918            .file()
19919            .and_then(|f| f.as_local())
19920    }
19921
19922    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19923        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19924            let buffer = buffer.read(cx);
19925            if let Some(project_path) = buffer.project_path(cx) {
19926                let project = self.project()?.read(cx);
19927                project.absolute_path(&project_path, cx)
19928            } else {
19929                buffer
19930                    .file()
19931                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19932            }
19933        })
19934    }
19935
19936    pub fn reveal_in_finder(
19937        &mut self,
19938        _: &RevealInFileManager,
19939        _window: &mut Window,
19940        cx: &mut Context<Self>,
19941    ) {
19942        if let Some(target) = self.target_file(cx) {
19943            cx.reveal_path(&target.abs_path(cx));
19944        }
19945    }
19946
19947    pub fn copy_path(
19948        &mut self,
19949        _: &zed_actions::workspace::CopyPath,
19950        _window: &mut Window,
19951        cx: &mut Context<Self>,
19952    ) {
19953        if let Some(path) = self.target_file_abs_path(cx)
19954            && let Some(path) = path.to_str()
19955        {
19956            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19957        } else {
19958            cx.propagate();
19959        }
19960    }
19961
19962    pub fn copy_relative_path(
19963        &mut self,
19964        _: &zed_actions::workspace::CopyRelativePath,
19965        _window: &mut Window,
19966        cx: &mut Context<Self>,
19967    ) {
19968        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19969            let project = self.project()?.read(cx);
19970            let path = buffer.read(cx).file()?.path();
19971            let path = path.display(project.path_style(cx));
19972            Some(path)
19973        }) {
19974            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19975        } else {
19976            cx.propagate();
19977        }
19978    }
19979
19980    /// Returns the project path for the editor's buffer, if any buffer is
19981    /// opened in the editor.
19982    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19983        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19984            buffer.read(cx).project_path(cx)
19985        } else {
19986            None
19987        }
19988    }
19989
19990    // Returns true if the editor handled a go-to-line request
19991    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19992        maybe!({
19993            let breakpoint_store = self.breakpoint_store.as_ref()?;
19994
19995            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19996            else {
19997                self.clear_row_highlights::<ActiveDebugLine>();
19998                return None;
19999            };
20000
20001            let position = active_stack_frame.position;
20002            let buffer_id = position.buffer_id?;
20003            let snapshot = self
20004                .project
20005                .as_ref()?
20006                .read(cx)
20007                .buffer_for_id(buffer_id, cx)?
20008                .read(cx)
20009                .snapshot();
20010
20011            let mut handled = false;
20012            for (id, ExcerptRange { context, .. }) in
20013                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20014            {
20015                if context.start.cmp(&position, &snapshot).is_ge()
20016                    || context.end.cmp(&position, &snapshot).is_lt()
20017                {
20018                    continue;
20019                }
20020                let snapshot = self.buffer.read(cx).snapshot(cx);
20021                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20022
20023                handled = true;
20024                self.clear_row_highlights::<ActiveDebugLine>();
20025
20026                self.go_to_line::<ActiveDebugLine>(
20027                    multibuffer_anchor,
20028                    Some(cx.theme().colors().editor_debugger_active_line_background),
20029                    window,
20030                    cx,
20031                );
20032
20033                cx.notify();
20034            }
20035
20036            handled.then_some(())
20037        })
20038        .is_some()
20039    }
20040
20041    pub fn copy_file_name_without_extension(
20042        &mut self,
20043        _: &CopyFileNameWithoutExtension,
20044        _: &mut Window,
20045        cx: &mut Context<Self>,
20046    ) {
20047        if let Some(file) = self.target_file(cx)
20048            && let Some(file_stem) = file.path().file_stem()
20049        {
20050            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20051        }
20052    }
20053
20054    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20055        if let Some(file) = self.target_file(cx)
20056            && let Some(name) = file.path().file_name()
20057        {
20058            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
20059        }
20060    }
20061
20062    pub fn toggle_git_blame(
20063        &mut self,
20064        _: &::git::Blame,
20065        window: &mut Window,
20066        cx: &mut Context<Self>,
20067    ) {
20068        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20069
20070        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20071            self.start_git_blame(true, window, cx);
20072        }
20073
20074        cx.notify();
20075    }
20076
20077    pub fn toggle_git_blame_inline(
20078        &mut self,
20079        _: &ToggleGitBlameInline,
20080        window: &mut Window,
20081        cx: &mut Context<Self>,
20082    ) {
20083        self.toggle_git_blame_inline_internal(true, window, cx);
20084        cx.notify();
20085    }
20086
20087    pub fn open_git_blame_commit(
20088        &mut self,
20089        _: &OpenGitBlameCommit,
20090        window: &mut Window,
20091        cx: &mut Context<Self>,
20092    ) {
20093        self.open_git_blame_commit_internal(window, cx);
20094    }
20095
20096    fn open_git_blame_commit_internal(
20097        &mut self,
20098        window: &mut Window,
20099        cx: &mut Context<Self>,
20100    ) -> Option<()> {
20101        let blame = self.blame.as_ref()?;
20102        let snapshot = self.snapshot(window, cx);
20103        let cursor = self
20104            .selections
20105            .newest::<Point>(&snapshot.display_snapshot)
20106            .head();
20107        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20108        let (_, blame_entry) = blame
20109            .update(cx, |blame, cx| {
20110                blame
20111                    .blame_for_rows(
20112                        &[RowInfo {
20113                            buffer_id: Some(buffer.remote_id()),
20114                            buffer_row: Some(point.row),
20115                            ..Default::default()
20116                        }],
20117                        cx,
20118                    )
20119                    .next()
20120            })
20121            .flatten()?;
20122        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20123        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20124        let workspace = self.workspace()?.downgrade();
20125        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20126        None
20127    }
20128
20129    pub fn git_blame_inline_enabled(&self) -> bool {
20130        self.git_blame_inline_enabled
20131    }
20132
20133    pub fn toggle_selection_menu(
20134        &mut self,
20135        _: &ToggleSelectionMenu,
20136        _: &mut Window,
20137        cx: &mut Context<Self>,
20138    ) {
20139        self.show_selection_menu = self
20140            .show_selection_menu
20141            .map(|show_selections_menu| !show_selections_menu)
20142            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20143
20144        cx.notify();
20145    }
20146
20147    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20148        self.show_selection_menu
20149            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20150    }
20151
20152    fn start_git_blame(
20153        &mut self,
20154        user_triggered: bool,
20155        window: &mut Window,
20156        cx: &mut Context<Self>,
20157    ) {
20158        if let Some(project) = self.project() {
20159            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20160                && buffer.read(cx).file().is_none()
20161            {
20162                return;
20163            }
20164
20165            let focused = self.focus_handle(cx).contains_focused(window, cx);
20166
20167            let project = project.clone();
20168            let blame = cx
20169                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20170            self.blame_subscription =
20171                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20172            self.blame = Some(blame);
20173        }
20174    }
20175
20176    fn toggle_git_blame_inline_internal(
20177        &mut self,
20178        user_triggered: bool,
20179        window: &mut Window,
20180        cx: &mut Context<Self>,
20181    ) {
20182        if self.git_blame_inline_enabled {
20183            self.git_blame_inline_enabled = false;
20184            self.show_git_blame_inline = false;
20185            self.show_git_blame_inline_delay_task.take();
20186        } else {
20187            self.git_blame_inline_enabled = true;
20188            self.start_git_blame_inline(user_triggered, window, cx);
20189        }
20190
20191        cx.notify();
20192    }
20193
20194    fn start_git_blame_inline(
20195        &mut self,
20196        user_triggered: bool,
20197        window: &mut Window,
20198        cx: &mut Context<Self>,
20199    ) {
20200        self.start_git_blame(user_triggered, window, cx);
20201
20202        if ProjectSettings::get_global(cx)
20203            .git
20204            .inline_blame_delay()
20205            .is_some()
20206        {
20207            self.start_inline_blame_timer(window, cx);
20208        } else {
20209            self.show_git_blame_inline = true
20210        }
20211    }
20212
20213    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20214        self.blame.as_ref()
20215    }
20216
20217    pub fn show_git_blame_gutter(&self) -> bool {
20218        self.show_git_blame_gutter
20219    }
20220
20221    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20222        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20223    }
20224
20225    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20226        self.show_git_blame_inline
20227            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20228            && !self.newest_selection_head_on_empty_line(cx)
20229            && self.has_blame_entries(cx)
20230    }
20231
20232    fn has_blame_entries(&self, cx: &App) -> bool {
20233        self.blame()
20234            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20235    }
20236
20237    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20238        let cursor_anchor = self.selections.newest_anchor().head();
20239
20240        let snapshot = self.buffer.read(cx).snapshot(cx);
20241        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20242
20243        snapshot.line_len(buffer_row) == 0
20244    }
20245
20246    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20247        let buffer_and_selection = maybe!({
20248            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20249            let selection_range = selection.range();
20250
20251            let multi_buffer = self.buffer().read(cx);
20252            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20253            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20254
20255            let (buffer, range, _) = if selection.reversed {
20256                buffer_ranges.first()
20257            } else {
20258                buffer_ranges.last()
20259            }?;
20260
20261            let selection = text::ToPoint::to_point(&range.start, buffer).row
20262                ..text::ToPoint::to_point(&range.end, buffer).row;
20263            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20264        });
20265
20266        let Some((buffer, selection)) = buffer_and_selection else {
20267            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20268        };
20269
20270        let Some(project) = self.project() else {
20271            return Task::ready(Err(anyhow!("editor does not have project")));
20272        };
20273
20274        project.update(cx, |project, cx| {
20275            project.get_permalink_to_line(&buffer, selection, cx)
20276        })
20277    }
20278
20279    pub fn copy_permalink_to_line(
20280        &mut self,
20281        _: &CopyPermalinkToLine,
20282        window: &mut Window,
20283        cx: &mut Context<Self>,
20284    ) {
20285        let permalink_task = self.get_permalink_to_line(cx);
20286        let workspace = self.workspace();
20287
20288        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20289            Ok(permalink) => {
20290                cx.update(|_, cx| {
20291                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20292                })
20293                .ok();
20294            }
20295            Err(err) => {
20296                let message = format!("Failed to copy permalink: {err}");
20297
20298                anyhow::Result::<()>::Err(err).log_err();
20299
20300                if let Some(workspace) = workspace {
20301                    workspace
20302                        .update_in(cx, |workspace, _, cx| {
20303                            struct CopyPermalinkToLine;
20304
20305                            workspace.show_toast(
20306                                Toast::new(
20307                                    NotificationId::unique::<CopyPermalinkToLine>(),
20308                                    message,
20309                                ),
20310                                cx,
20311                            )
20312                        })
20313                        .ok();
20314                }
20315            }
20316        })
20317        .detach();
20318    }
20319
20320    pub fn copy_file_location(
20321        &mut self,
20322        _: &CopyFileLocation,
20323        _: &mut Window,
20324        cx: &mut Context<Self>,
20325    ) {
20326        let selection = self
20327            .selections
20328            .newest::<Point>(&self.display_snapshot(cx))
20329            .start
20330            .row
20331            + 1;
20332        if let Some(file) = self.target_file(cx) {
20333            let path = file.path().display(file.path_style(cx));
20334            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20335        }
20336    }
20337
20338    pub fn open_permalink_to_line(
20339        &mut self,
20340        _: &OpenPermalinkToLine,
20341        window: &mut Window,
20342        cx: &mut Context<Self>,
20343    ) {
20344        let permalink_task = self.get_permalink_to_line(cx);
20345        let workspace = self.workspace();
20346
20347        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20348            Ok(permalink) => {
20349                cx.update(|_, cx| {
20350                    cx.open_url(permalink.as_ref());
20351                })
20352                .ok();
20353            }
20354            Err(err) => {
20355                let message = format!("Failed to open permalink: {err}");
20356
20357                anyhow::Result::<()>::Err(err).log_err();
20358
20359                if let Some(workspace) = workspace {
20360                    workspace
20361                        .update(cx, |workspace, cx| {
20362                            struct OpenPermalinkToLine;
20363
20364                            workspace.show_toast(
20365                                Toast::new(
20366                                    NotificationId::unique::<OpenPermalinkToLine>(),
20367                                    message,
20368                                ),
20369                                cx,
20370                            )
20371                        })
20372                        .ok();
20373                }
20374            }
20375        })
20376        .detach();
20377    }
20378
20379    pub fn insert_uuid_v4(
20380        &mut self,
20381        _: &InsertUuidV4,
20382        window: &mut Window,
20383        cx: &mut Context<Self>,
20384    ) {
20385        self.insert_uuid(UuidVersion::V4, window, cx);
20386    }
20387
20388    pub fn insert_uuid_v7(
20389        &mut self,
20390        _: &InsertUuidV7,
20391        window: &mut Window,
20392        cx: &mut Context<Self>,
20393    ) {
20394        self.insert_uuid(UuidVersion::V7, window, cx);
20395    }
20396
20397    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20398        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20399        self.transact(window, cx, |this, window, cx| {
20400            let edits = this
20401                .selections
20402                .all::<Point>(&this.display_snapshot(cx))
20403                .into_iter()
20404                .map(|selection| {
20405                    let uuid = match version {
20406                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20407                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20408                    };
20409
20410                    (selection.range(), uuid.to_string())
20411                });
20412            this.edit(edits, cx);
20413            this.refresh_edit_prediction(true, false, window, cx);
20414        });
20415    }
20416
20417    pub fn open_selections_in_multibuffer(
20418        &mut self,
20419        _: &OpenSelectionsInMultibuffer,
20420        window: &mut Window,
20421        cx: &mut Context<Self>,
20422    ) {
20423        let multibuffer = self.buffer.read(cx);
20424
20425        let Some(buffer) = multibuffer.as_singleton() else {
20426            return;
20427        };
20428
20429        let Some(workspace) = self.workspace() else {
20430            return;
20431        };
20432
20433        let title = multibuffer.title(cx).to_string();
20434
20435        let locations = self
20436            .selections
20437            .all_anchors(&self.display_snapshot(cx))
20438            .iter()
20439            .map(|selection| {
20440                (
20441                    buffer.clone(),
20442                    (selection.start.text_anchor..selection.end.text_anchor)
20443                        .to_point(buffer.read(cx)),
20444                )
20445            })
20446            .into_group_map();
20447
20448        cx.spawn_in(window, async move |_, cx| {
20449            workspace.update_in(cx, |workspace, window, cx| {
20450                Self::open_locations_in_multibuffer(
20451                    workspace,
20452                    locations,
20453                    format!("Selections for '{title}'"),
20454                    false,
20455                    MultibufferSelectionMode::All,
20456                    window,
20457                    cx,
20458                );
20459            })
20460        })
20461        .detach();
20462    }
20463
20464    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20465    /// last highlight added will be used.
20466    ///
20467    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20468    pub fn highlight_rows<T: 'static>(
20469        &mut self,
20470        range: Range<Anchor>,
20471        color: Hsla,
20472        options: RowHighlightOptions,
20473        cx: &mut Context<Self>,
20474    ) {
20475        let snapshot = self.buffer().read(cx).snapshot(cx);
20476        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20477        let ix = row_highlights.binary_search_by(|highlight| {
20478            Ordering::Equal
20479                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20480                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20481        });
20482
20483        if let Err(mut ix) = ix {
20484            let index = post_inc(&mut self.highlight_order);
20485
20486            // If this range intersects with the preceding highlight, then merge it with
20487            // the preceding highlight. Otherwise insert a new highlight.
20488            let mut merged = false;
20489            if ix > 0 {
20490                let prev_highlight = &mut row_highlights[ix - 1];
20491                if prev_highlight
20492                    .range
20493                    .end
20494                    .cmp(&range.start, &snapshot)
20495                    .is_ge()
20496                {
20497                    ix -= 1;
20498                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20499                        prev_highlight.range.end = range.end;
20500                    }
20501                    merged = true;
20502                    prev_highlight.index = index;
20503                    prev_highlight.color = color;
20504                    prev_highlight.options = options;
20505                }
20506            }
20507
20508            if !merged {
20509                row_highlights.insert(
20510                    ix,
20511                    RowHighlight {
20512                        range,
20513                        index,
20514                        color,
20515                        options,
20516                        type_id: TypeId::of::<T>(),
20517                    },
20518                );
20519            }
20520
20521            // If any of the following highlights intersect with this one, merge them.
20522            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20523                let highlight = &row_highlights[ix];
20524                if next_highlight
20525                    .range
20526                    .start
20527                    .cmp(&highlight.range.end, &snapshot)
20528                    .is_le()
20529                {
20530                    if next_highlight
20531                        .range
20532                        .end
20533                        .cmp(&highlight.range.end, &snapshot)
20534                        .is_gt()
20535                    {
20536                        row_highlights[ix].range.end = next_highlight.range.end;
20537                    }
20538                    row_highlights.remove(ix + 1);
20539                } else {
20540                    break;
20541                }
20542            }
20543        }
20544    }
20545
20546    /// Remove any highlighted row ranges of the given type that intersect the
20547    /// given ranges.
20548    pub fn remove_highlighted_rows<T: 'static>(
20549        &mut self,
20550        ranges_to_remove: Vec<Range<Anchor>>,
20551        cx: &mut Context<Self>,
20552    ) {
20553        let snapshot = self.buffer().read(cx).snapshot(cx);
20554        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20555        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20556        row_highlights.retain(|highlight| {
20557            while let Some(range_to_remove) = ranges_to_remove.peek() {
20558                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20559                    Ordering::Less | Ordering::Equal => {
20560                        ranges_to_remove.next();
20561                    }
20562                    Ordering::Greater => {
20563                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20564                            Ordering::Less | Ordering::Equal => {
20565                                return false;
20566                            }
20567                            Ordering::Greater => break,
20568                        }
20569                    }
20570                }
20571            }
20572
20573            true
20574        })
20575    }
20576
20577    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20578    pub fn clear_row_highlights<T: 'static>(&mut self) {
20579        self.highlighted_rows.remove(&TypeId::of::<T>());
20580    }
20581
20582    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20583    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20584        self.highlighted_rows
20585            .get(&TypeId::of::<T>())
20586            .map_or(&[] as &[_], |vec| vec.as_slice())
20587            .iter()
20588            .map(|highlight| (highlight.range.clone(), highlight.color))
20589    }
20590
20591    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20592    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20593    /// Allows to ignore certain kinds of highlights.
20594    pub fn highlighted_display_rows(
20595        &self,
20596        window: &mut Window,
20597        cx: &mut App,
20598    ) -> BTreeMap<DisplayRow, LineHighlight> {
20599        let snapshot = self.snapshot(window, cx);
20600        let mut used_highlight_orders = HashMap::default();
20601        self.highlighted_rows
20602            .iter()
20603            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20604            .fold(
20605                BTreeMap::<DisplayRow, LineHighlight>::new(),
20606                |mut unique_rows, highlight| {
20607                    let start = highlight.range.start.to_display_point(&snapshot);
20608                    let end = highlight.range.end.to_display_point(&snapshot);
20609                    let start_row = start.row().0;
20610                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20611                        && end.column() == 0
20612                    {
20613                        end.row().0.saturating_sub(1)
20614                    } else {
20615                        end.row().0
20616                    };
20617                    for row in start_row..=end_row {
20618                        let used_index =
20619                            used_highlight_orders.entry(row).or_insert(highlight.index);
20620                        if highlight.index >= *used_index {
20621                            *used_index = highlight.index;
20622                            unique_rows.insert(
20623                                DisplayRow(row),
20624                                LineHighlight {
20625                                    include_gutter: highlight.options.include_gutter,
20626                                    border: None,
20627                                    background: highlight.color.into(),
20628                                    type_id: Some(highlight.type_id),
20629                                },
20630                            );
20631                        }
20632                    }
20633                    unique_rows
20634                },
20635            )
20636    }
20637
20638    pub fn highlighted_display_row_for_autoscroll(
20639        &self,
20640        snapshot: &DisplaySnapshot,
20641    ) -> Option<DisplayRow> {
20642        self.highlighted_rows
20643            .values()
20644            .flat_map(|highlighted_rows| highlighted_rows.iter())
20645            .filter_map(|highlight| {
20646                if highlight.options.autoscroll {
20647                    Some(highlight.range.start.to_display_point(snapshot).row())
20648                } else {
20649                    None
20650                }
20651            })
20652            .min()
20653    }
20654
20655    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20656        self.highlight_background::<SearchWithinRange>(
20657            ranges,
20658            |colors| colors.colors().editor_document_highlight_read_background,
20659            cx,
20660        )
20661    }
20662
20663    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20664        self.breadcrumb_header = Some(new_header);
20665    }
20666
20667    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20668        self.clear_background_highlights::<SearchWithinRange>(cx);
20669    }
20670
20671    pub fn highlight_background<T: 'static>(
20672        &mut self,
20673        ranges: &[Range<Anchor>],
20674        color_fetcher: fn(&Theme) -> Hsla,
20675        cx: &mut Context<Self>,
20676    ) {
20677        self.background_highlights.insert(
20678            HighlightKey::Type(TypeId::of::<T>()),
20679            (color_fetcher, Arc::from(ranges)),
20680        );
20681        self.scrollbar_marker_state.dirty = true;
20682        cx.notify();
20683    }
20684
20685    pub fn highlight_background_key<T: 'static>(
20686        &mut self,
20687        key: usize,
20688        ranges: &[Range<Anchor>],
20689        color_fetcher: fn(&Theme) -> Hsla,
20690        cx: &mut Context<Self>,
20691    ) {
20692        self.background_highlights.insert(
20693            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20694            (color_fetcher, Arc::from(ranges)),
20695        );
20696        self.scrollbar_marker_state.dirty = true;
20697        cx.notify();
20698    }
20699
20700    pub fn clear_background_highlights<T: 'static>(
20701        &mut self,
20702        cx: &mut Context<Self>,
20703    ) -> Option<BackgroundHighlight> {
20704        let text_highlights = self
20705            .background_highlights
20706            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20707        if !text_highlights.1.is_empty() {
20708            self.scrollbar_marker_state.dirty = true;
20709            cx.notify();
20710        }
20711        Some(text_highlights)
20712    }
20713
20714    pub fn highlight_gutter<T: 'static>(
20715        &mut self,
20716        ranges: impl Into<Vec<Range<Anchor>>>,
20717        color_fetcher: fn(&App) -> Hsla,
20718        cx: &mut Context<Self>,
20719    ) {
20720        self.gutter_highlights
20721            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20722        cx.notify();
20723    }
20724
20725    pub fn clear_gutter_highlights<T: 'static>(
20726        &mut self,
20727        cx: &mut Context<Self>,
20728    ) -> Option<GutterHighlight> {
20729        cx.notify();
20730        self.gutter_highlights.remove(&TypeId::of::<T>())
20731    }
20732
20733    pub fn insert_gutter_highlight<T: 'static>(
20734        &mut self,
20735        range: Range<Anchor>,
20736        color_fetcher: fn(&App) -> Hsla,
20737        cx: &mut Context<Self>,
20738    ) {
20739        let snapshot = self.buffer().read(cx).snapshot(cx);
20740        let mut highlights = self
20741            .gutter_highlights
20742            .remove(&TypeId::of::<T>())
20743            .map(|(_, highlights)| highlights)
20744            .unwrap_or_default();
20745        let ix = highlights.binary_search_by(|highlight| {
20746            Ordering::Equal
20747                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20748                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20749        });
20750        if let Err(ix) = ix {
20751            highlights.insert(ix, range);
20752        }
20753        self.gutter_highlights
20754            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20755    }
20756
20757    pub fn remove_gutter_highlights<T: 'static>(
20758        &mut self,
20759        ranges_to_remove: Vec<Range<Anchor>>,
20760        cx: &mut Context<Self>,
20761    ) {
20762        let snapshot = self.buffer().read(cx).snapshot(cx);
20763        let Some((color_fetcher, mut gutter_highlights)) =
20764            self.gutter_highlights.remove(&TypeId::of::<T>())
20765        else {
20766            return;
20767        };
20768        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20769        gutter_highlights.retain(|highlight| {
20770            while let Some(range_to_remove) = ranges_to_remove.peek() {
20771                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20772                    Ordering::Less | Ordering::Equal => {
20773                        ranges_to_remove.next();
20774                    }
20775                    Ordering::Greater => {
20776                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20777                            Ordering::Less | Ordering::Equal => {
20778                                return false;
20779                            }
20780                            Ordering::Greater => break,
20781                        }
20782                    }
20783                }
20784            }
20785
20786            true
20787        });
20788        self.gutter_highlights
20789            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20790    }
20791
20792    #[cfg(feature = "test-support")]
20793    pub fn all_text_highlights(
20794        &self,
20795        window: &mut Window,
20796        cx: &mut Context<Self>,
20797    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20798        let snapshot = self.snapshot(window, cx);
20799        self.display_map.update(cx, |display_map, _| {
20800            display_map
20801                .all_text_highlights()
20802                .map(|highlight| {
20803                    let (style, ranges) = highlight.as_ref();
20804                    (
20805                        *style,
20806                        ranges
20807                            .iter()
20808                            .map(|range| range.clone().to_display_points(&snapshot))
20809                            .collect(),
20810                    )
20811                })
20812                .collect()
20813        })
20814    }
20815
20816    #[cfg(feature = "test-support")]
20817    pub fn all_text_background_highlights(
20818        &self,
20819        window: &mut Window,
20820        cx: &mut Context<Self>,
20821    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20822        let snapshot = self.snapshot(window, cx);
20823        let buffer = &snapshot.buffer_snapshot();
20824        let start = buffer.anchor_before(0);
20825        let end = buffer.anchor_after(buffer.len());
20826        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20827    }
20828
20829    #[cfg(any(test, feature = "test-support"))]
20830    pub fn sorted_background_highlights_in_range(
20831        &self,
20832        search_range: Range<Anchor>,
20833        display_snapshot: &DisplaySnapshot,
20834        theme: &Theme,
20835    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20836        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20837        res.sort_by(|a, b| {
20838            a.0.start
20839                .cmp(&b.0.start)
20840                .then_with(|| a.0.end.cmp(&b.0.end))
20841                .then_with(|| a.1.cmp(&b.1))
20842        });
20843        res
20844    }
20845
20846    #[cfg(feature = "test-support")]
20847    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20848        let snapshot = self.buffer().read(cx).snapshot(cx);
20849
20850        let highlights = self
20851            .background_highlights
20852            .get(&HighlightKey::Type(TypeId::of::<
20853                items::BufferSearchHighlights,
20854            >()));
20855
20856        if let Some((_color, ranges)) = highlights {
20857            ranges
20858                .iter()
20859                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20860                .collect_vec()
20861        } else {
20862            vec![]
20863        }
20864    }
20865
20866    fn document_highlights_for_position<'a>(
20867        &'a self,
20868        position: Anchor,
20869        buffer: &'a MultiBufferSnapshot,
20870    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20871        let read_highlights = self
20872            .background_highlights
20873            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20874            .map(|h| &h.1);
20875        let write_highlights = self
20876            .background_highlights
20877            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20878            .map(|h| &h.1);
20879        let left_position = position.bias_left(buffer);
20880        let right_position = position.bias_right(buffer);
20881        read_highlights
20882            .into_iter()
20883            .chain(write_highlights)
20884            .flat_map(move |ranges| {
20885                let start_ix = match ranges.binary_search_by(|probe| {
20886                    let cmp = probe.end.cmp(&left_position, buffer);
20887                    if cmp.is_ge() {
20888                        Ordering::Greater
20889                    } else {
20890                        Ordering::Less
20891                    }
20892                }) {
20893                    Ok(i) | Err(i) => i,
20894                };
20895
20896                ranges[start_ix..]
20897                    .iter()
20898                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20899            })
20900    }
20901
20902    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20903        self.background_highlights
20904            .get(&HighlightKey::Type(TypeId::of::<T>()))
20905            .is_some_and(|(_, highlights)| !highlights.is_empty())
20906    }
20907
20908    /// Returns all background highlights for a given range.
20909    ///
20910    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20911    pub fn background_highlights_in_range(
20912        &self,
20913        search_range: Range<Anchor>,
20914        display_snapshot: &DisplaySnapshot,
20915        theme: &Theme,
20916    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20917        let mut results = Vec::new();
20918        for (color_fetcher, ranges) in self.background_highlights.values() {
20919            let color = color_fetcher(theme);
20920            let start_ix = match ranges.binary_search_by(|probe| {
20921                let cmp = probe
20922                    .end
20923                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20924                if cmp.is_gt() {
20925                    Ordering::Greater
20926                } else {
20927                    Ordering::Less
20928                }
20929            }) {
20930                Ok(i) | Err(i) => i,
20931            };
20932            for range in &ranges[start_ix..] {
20933                if range
20934                    .start
20935                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20936                    .is_ge()
20937                {
20938                    break;
20939                }
20940
20941                let start = range.start.to_display_point(display_snapshot);
20942                let end = range.end.to_display_point(display_snapshot);
20943                results.push((start..end, color))
20944            }
20945        }
20946        results
20947    }
20948
20949    pub fn gutter_highlights_in_range(
20950        &self,
20951        search_range: Range<Anchor>,
20952        display_snapshot: &DisplaySnapshot,
20953        cx: &App,
20954    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20955        let mut results = Vec::new();
20956        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20957            let color = color_fetcher(cx);
20958            let start_ix = match ranges.binary_search_by(|probe| {
20959                let cmp = probe
20960                    .end
20961                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20962                if cmp.is_gt() {
20963                    Ordering::Greater
20964                } else {
20965                    Ordering::Less
20966                }
20967            }) {
20968                Ok(i) | Err(i) => i,
20969            };
20970            for range in &ranges[start_ix..] {
20971                if range
20972                    .start
20973                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20974                    .is_ge()
20975                {
20976                    break;
20977                }
20978
20979                let start = range.start.to_display_point(display_snapshot);
20980                let end = range.end.to_display_point(display_snapshot);
20981                results.push((start..end, color))
20982            }
20983        }
20984        results
20985    }
20986
20987    /// Get the text ranges corresponding to the redaction query
20988    pub fn redacted_ranges(
20989        &self,
20990        search_range: Range<Anchor>,
20991        display_snapshot: &DisplaySnapshot,
20992        cx: &App,
20993    ) -> Vec<Range<DisplayPoint>> {
20994        display_snapshot
20995            .buffer_snapshot()
20996            .redacted_ranges(search_range, |file| {
20997                if let Some(file) = file {
20998                    file.is_private()
20999                        && EditorSettings::get(
21000                            Some(SettingsLocation {
21001                                worktree_id: file.worktree_id(cx),
21002                                path: file.path().as_ref(),
21003                            }),
21004                            cx,
21005                        )
21006                        .redact_private_values
21007                } else {
21008                    false
21009                }
21010            })
21011            .map(|range| {
21012                range.start.to_display_point(display_snapshot)
21013                    ..range.end.to_display_point(display_snapshot)
21014            })
21015            .collect()
21016    }
21017
21018    pub fn highlight_text_key<T: 'static>(
21019        &mut self,
21020        key: usize,
21021        ranges: Vec<Range<Anchor>>,
21022        style: HighlightStyle,
21023        cx: &mut Context<Self>,
21024    ) {
21025        self.display_map.update(cx, |map, _| {
21026            map.highlight_text(
21027                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21028                ranges,
21029                style,
21030            );
21031        });
21032        cx.notify();
21033    }
21034
21035    pub fn highlight_text<T: 'static>(
21036        &mut self,
21037        ranges: Vec<Range<Anchor>>,
21038        style: HighlightStyle,
21039        cx: &mut Context<Self>,
21040    ) {
21041        self.display_map.update(cx, |map, _| {
21042            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
21043        });
21044        cx.notify();
21045    }
21046
21047    pub fn text_highlights<'a, T: 'static>(
21048        &'a self,
21049        cx: &'a App,
21050    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21051        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21052    }
21053
21054    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21055        let cleared = self
21056            .display_map
21057            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21058        if cleared {
21059            cx.notify();
21060        }
21061    }
21062
21063    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21064        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21065            && self.focus_handle.is_focused(window)
21066    }
21067
21068    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21069        self.show_cursor_when_unfocused = is_enabled;
21070        cx.notify();
21071    }
21072
21073    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21074        cx.notify();
21075    }
21076
21077    fn on_debug_session_event(
21078        &mut self,
21079        _session: Entity<Session>,
21080        event: &SessionEvent,
21081        cx: &mut Context<Self>,
21082    ) {
21083        if let SessionEvent::InvalidateInlineValue = event {
21084            self.refresh_inline_values(cx);
21085        }
21086    }
21087
21088    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21089        let Some(project) = self.project.clone() else {
21090            return;
21091        };
21092
21093        if !self.inline_value_cache.enabled {
21094            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21095            self.splice_inlays(&inlays, Vec::new(), cx);
21096            return;
21097        }
21098
21099        let current_execution_position = self
21100            .highlighted_rows
21101            .get(&TypeId::of::<ActiveDebugLine>())
21102            .and_then(|lines| lines.last().map(|line| line.range.end));
21103
21104        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21105            let inline_values = editor
21106                .update(cx, |editor, cx| {
21107                    let Some(current_execution_position) = current_execution_position else {
21108                        return Some(Task::ready(Ok(Vec::new())));
21109                    };
21110
21111                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21112                        let snapshot = buffer.snapshot(cx);
21113
21114                        let excerpt = snapshot.excerpt_containing(
21115                            current_execution_position..current_execution_position,
21116                        )?;
21117
21118                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21119                    })?;
21120
21121                    let range =
21122                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21123
21124                    project.inline_values(buffer, range, cx)
21125                })
21126                .ok()
21127                .flatten()?
21128                .await
21129                .context("refreshing debugger inlays")
21130                .log_err()?;
21131
21132            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21133
21134            for (buffer_id, inline_value) in inline_values
21135                .into_iter()
21136                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21137            {
21138                buffer_inline_values
21139                    .entry(buffer_id)
21140                    .or_default()
21141                    .push(inline_value);
21142            }
21143
21144            editor
21145                .update(cx, |editor, cx| {
21146                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21147                    let mut new_inlays = Vec::default();
21148
21149                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21150                        let buffer_id = buffer_snapshot.remote_id();
21151                        buffer_inline_values
21152                            .get(&buffer_id)
21153                            .into_iter()
21154                            .flatten()
21155                            .for_each(|hint| {
21156                                let inlay = Inlay::debugger(
21157                                    post_inc(&mut editor.next_inlay_id),
21158                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21159                                    hint.text(),
21160                                );
21161                                if !inlay.text().chars().contains(&'\n') {
21162                                    new_inlays.push(inlay);
21163                                }
21164                            });
21165                    }
21166
21167                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21168                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21169
21170                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21171                })
21172                .ok()?;
21173            Some(())
21174        });
21175    }
21176
21177    fn on_buffer_event(
21178        &mut self,
21179        multibuffer: &Entity<MultiBuffer>,
21180        event: &multi_buffer::Event,
21181        window: &mut Window,
21182        cx: &mut Context<Self>,
21183    ) {
21184        match event {
21185            multi_buffer::Event::Edited { edited_buffer } => {
21186                self.scrollbar_marker_state.dirty = true;
21187                self.active_indent_guides_state.dirty = true;
21188                self.refresh_active_diagnostics(cx);
21189                self.refresh_code_actions(window, cx);
21190                self.refresh_selected_text_highlights(true, window, cx);
21191                self.refresh_single_line_folds(window, cx);
21192                self.refresh_matching_bracket_highlights(window, cx);
21193                if self.has_active_edit_prediction() {
21194                    self.update_visible_edit_prediction(window, cx);
21195                }
21196
21197                if let Some(buffer) = edited_buffer {
21198                    if buffer.read(cx).file().is_none() {
21199                        cx.emit(EditorEvent::TitleChanged);
21200                    }
21201
21202                    if self.project.is_some() {
21203                        let buffer_id = buffer.read(cx).remote_id();
21204                        self.register_buffer(buffer_id, cx);
21205                        self.update_lsp_data(Some(buffer_id), window, cx);
21206                        self.refresh_inlay_hints(
21207                            InlayHintRefreshReason::BufferEdited(buffer_id),
21208                            cx,
21209                        );
21210                    }
21211                }
21212
21213                cx.emit(EditorEvent::BufferEdited);
21214                cx.emit(SearchEvent::MatchesInvalidated);
21215
21216                let Some(project) = &self.project else { return };
21217                let (telemetry, is_via_ssh) = {
21218                    let project = project.read(cx);
21219                    let telemetry = project.client().telemetry().clone();
21220                    let is_via_ssh = project.is_via_remote_server();
21221                    (telemetry, is_via_ssh)
21222                };
21223                telemetry.log_edit_event("editor", is_via_ssh);
21224            }
21225            multi_buffer::Event::ExcerptsAdded {
21226                buffer,
21227                predecessor,
21228                excerpts,
21229            } => {
21230                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21231                let buffer_id = buffer.read(cx).remote_id();
21232                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21233                    && let Some(project) = &self.project
21234                {
21235                    update_uncommitted_diff_for_buffer(
21236                        cx.entity(),
21237                        project,
21238                        [buffer.clone()],
21239                        self.buffer.clone(),
21240                        cx,
21241                    )
21242                    .detach();
21243                }
21244                self.update_lsp_data(Some(buffer_id), window, cx);
21245                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21246                cx.emit(EditorEvent::ExcerptsAdded {
21247                    buffer: buffer.clone(),
21248                    predecessor: *predecessor,
21249                    excerpts: excerpts.clone(),
21250                });
21251            }
21252            multi_buffer::Event::ExcerptsRemoved {
21253                ids,
21254                removed_buffer_ids,
21255            } => {
21256                if let Some(inlay_hints) = &mut self.inlay_hints {
21257                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21258                }
21259                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21260                for buffer_id in removed_buffer_ids {
21261                    self.registered_buffers.remove(buffer_id);
21262                }
21263                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21264                cx.emit(EditorEvent::ExcerptsRemoved {
21265                    ids: ids.clone(),
21266                    removed_buffer_ids: removed_buffer_ids.clone(),
21267                });
21268            }
21269            multi_buffer::Event::ExcerptsEdited {
21270                excerpt_ids,
21271                buffer_ids,
21272            } => {
21273                self.display_map.update(cx, |map, cx| {
21274                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21275                });
21276                cx.emit(EditorEvent::ExcerptsEdited {
21277                    ids: excerpt_ids.clone(),
21278                });
21279            }
21280            multi_buffer::Event::ExcerptsExpanded { ids } => {
21281                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21282                self.refresh_document_highlights(cx);
21283                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21284            }
21285            multi_buffer::Event::Reparsed(buffer_id) => {
21286                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21287                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21288
21289                cx.emit(EditorEvent::Reparsed(*buffer_id));
21290            }
21291            multi_buffer::Event::DiffHunksToggled => {
21292                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21293            }
21294            multi_buffer::Event::LanguageChanged(buffer_id) => {
21295                self.registered_buffers.remove(&buffer_id);
21296                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21297                cx.emit(EditorEvent::Reparsed(*buffer_id));
21298                cx.notify();
21299            }
21300            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21301            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21302            multi_buffer::Event::FileHandleChanged
21303            | multi_buffer::Event::Reloaded
21304            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21305            multi_buffer::Event::DiagnosticsUpdated => {
21306                self.update_diagnostics_state(window, cx);
21307            }
21308            _ => {}
21309        };
21310    }
21311
21312    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21313        if !self.diagnostics_enabled() {
21314            return;
21315        }
21316        self.refresh_active_diagnostics(cx);
21317        self.refresh_inline_diagnostics(true, window, cx);
21318        self.scrollbar_marker_state.dirty = true;
21319        cx.notify();
21320    }
21321
21322    pub fn start_temporary_diff_override(&mut self) {
21323        self.load_diff_task.take();
21324        self.temporary_diff_override = true;
21325    }
21326
21327    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21328        self.temporary_diff_override = false;
21329        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21330        self.buffer.update(cx, |buffer, cx| {
21331            buffer.set_all_diff_hunks_collapsed(cx);
21332        });
21333
21334        if let Some(project) = self.project.clone() {
21335            self.load_diff_task = Some(
21336                update_uncommitted_diff_for_buffer(
21337                    cx.entity(),
21338                    &project,
21339                    self.buffer.read(cx).all_buffers(),
21340                    self.buffer.clone(),
21341                    cx,
21342                )
21343                .shared(),
21344            );
21345        }
21346    }
21347
21348    fn on_display_map_changed(
21349        &mut self,
21350        _: Entity<DisplayMap>,
21351        _: &mut Window,
21352        cx: &mut Context<Self>,
21353    ) {
21354        cx.notify();
21355    }
21356
21357    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21358        if self.diagnostics_enabled() {
21359            let new_severity = EditorSettings::get_global(cx)
21360                .diagnostics_max_severity
21361                .unwrap_or(DiagnosticSeverity::Hint);
21362            self.set_max_diagnostics_severity(new_severity, cx);
21363        }
21364        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21365        self.update_edit_prediction_settings(cx);
21366        self.refresh_edit_prediction(true, false, window, cx);
21367        self.refresh_inline_values(cx);
21368        self.refresh_inlay_hints(
21369            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21370                self.selections.newest_anchor().head(),
21371                &self.buffer.read(cx).snapshot(cx),
21372                cx,
21373            )),
21374            cx,
21375        );
21376
21377        let old_cursor_shape = self.cursor_shape;
21378        let old_show_breadcrumbs = self.show_breadcrumbs;
21379
21380        {
21381            let editor_settings = EditorSettings::get_global(cx);
21382            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21383            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21384            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21385            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21386        }
21387
21388        if old_cursor_shape != self.cursor_shape {
21389            cx.emit(EditorEvent::CursorShapeChanged);
21390        }
21391
21392        if old_show_breadcrumbs != self.show_breadcrumbs {
21393            cx.emit(EditorEvent::BreadcrumbsChanged);
21394        }
21395
21396        let project_settings = ProjectSettings::get_global(cx);
21397        self.buffer_serialization = self
21398            .should_serialize_buffer()
21399            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21400
21401        if self.mode.is_full() {
21402            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21403            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21404            if self.show_inline_diagnostics != show_inline_diagnostics {
21405                self.show_inline_diagnostics = show_inline_diagnostics;
21406                self.refresh_inline_diagnostics(false, window, cx);
21407            }
21408
21409            if self.git_blame_inline_enabled != inline_blame_enabled {
21410                self.toggle_git_blame_inline_internal(false, window, cx);
21411            }
21412
21413            let minimap_settings = EditorSettings::get_global(cx).minimap;
21414            if self.minimap_visibility != MinimapVisibility::Disabled {
21415                if self.minimap_visibility.settings_visibility()
21416                    != minimap_settings.minimap_enabled()
21417                {
21418                    self.set_minimap_visibility(
21419                        MinimapVisibility::for_mode(self.mode(), cx),
21420                        window,
21421                        cx,
21422                    );
21423                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21424                    minimap_entity.update(cx, |minimap_editor, cx| {
21425                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21426                    })
21427                }
21428            }
21429        }
21430
21431        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21432            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21433        }) {
21434            if !inlay_splice.is_empty() {
21435                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21436            }
21437            self.refresh_colors_for_visible_range(None, window, cx);
21438        }
21439
21440        cx.notify();
21441    }
21442
21443    pub fn set_searchable(&mut self, searchable: bool) {
21444        self.searchable = searchable;
21445    }
21446
21447    pub fn searchable(&self) -> bool {
21448        self.searchable
21449    }
21450
21451    pub fn open_excerpts_in_split(
21452        &mut self,
21453        _: &OpenExcerptsSplit,
21454        window: &mut Window,
21455        cx: &mut Context<Self>,
21456    ) {
21457        self.open_excerpts_common(None, true, window, cx)
21458    }
21459
21460    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21461        self.open_excerpts_common(None, false, window, cx)
21462    }
21463
21464    fn open_excerpts_common(
21465        &mut self,
21466        jump_data: Option<JumpData>,
21467        split: bool,
21468        window: &mut Window,
21469        cx: &mut Context<Self>,
21470    ) {
21471        let Some(workspace) = self.workspace() else {
21472            cx.propagate();
21473            return;
21474        };
21475
21476        if self.buffer.read(cx).is_singleton() {
21477            cx.propagate();
21478            return;
21479        }
21480
21481        let mut new_selections_by_buffer = HashMap::default();
21482        match &jump_data {
21483            Some(JumpData::MultiBufferPoint {
21484                excerpt_id,
21485                position,
21486                anchor,
21487                line_offset_from_top,
21488            }) => {
21489                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21490                if let Some(buffer) = multi_buffer_snapshot
21491                    .buffer_id_for_excerpt(*excerpt_id)
21492                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21493                {
21494                    let buffer_snapshot = buffer.read(cx).snapshot();
21495                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21496                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21497                    } else {
21498                        buffer_snapshot.clip_point(*position, Bias::Left)
21499                    };
21500                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21501                    new_selections_by_buffer.insert(
21502                        buffer,
21503                        (
21504                            vec![jump_to_offset..jump_to_offset],
21505                            Some(*line_offset_from_top),
21506                        ),
21507                    );
21508                }
21509            }
21510            Some(JumpData::MultiBufferRow {
21511                row,
21512                line_offset_from_top,
21513            }) => {
21514                let point = MultiBufferPoint::new(row.0, 0);
21515                if let Some((buffer, buffer_point, _)) =
21516                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21517                {
21518                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21519                    new_selections_by_buffer
21520                        .entry(buffer)
21521                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21522                        .0
21523                        .push(buffer_offset..buffer_offset)
21524                }
21525            }
21526            None => {
21527                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21528                let multi_buffer = self.buffer.read(cx);
21529                for selection in selections {
21530                    for (snapshot, range, _, anchor) in multi_buffer
21531                        .snapshot(cx)
21532                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21533                    {
21534                        if let Some(anchor) = anchor {
21535                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21536                            else {
21537                                continue;
21538                            };
21539                            let offset = text::ToOffset::to_offset(
21540                                &anchor.text_anchor,
21541                                &buffer_handle.read(cx).snapshot(),
21542                            );
21543                            let range = offset..offset;
21544                            new_selections_by_buffer
21545                                .entry(buffer_handle)
21546                                .or_insert((Vec::new(), None))
21547                                .0
21548                                .push(range)
21549                        } else {
21550                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21551                            else {
21552                                continue;
21553                            };
21554                            new_selections_by_buffer
21555                                .entry(buffer_handle)
21556                                .or_insert((Vec::new(), None))
21557                                .0
21558                                .push(range)
21559                        }
21560                    }
21561                }
21562            }
21563        }
21564
21565        new_selections_by_buffer
21566            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21567
21568        if new_selections_by_buffer.is_empty() {
21569            return;
21570        }
21571
21572        // We defer the pane interaction because we ourselves are a workspace item
21573        // and activating a new item causes the pane to call a method on us reentrantly,
21574        // which panics if we're on the stack.
21575        window.defer(cx, move |window, cx| {
21576            workspace.update(cx, |workspace, cx| {
21577                let pane = if split {
21578                    workspace.adjacent_pane(window, cx)
21579                } else {
21580                    workspace.active_pane().clone()
21581                };
21582
21583                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21584                    let editor = buffer
21585                        .read(cx)
21586                        .file()
21587                        .is_none()
21588                        .then(|| {
21589                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21590                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21591                            // Instead, we try to activate the existing editor in the pane first.
21592                            let (editor, pane_item_index) =
21593                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21594                                    let editor = item.downcast::<Editor>()?;
21595                                    let singleton_buffer =
21596                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21597                                    if singleton_buffer == buffer {
21598                                        Some((editor, i))
21599                                    } else {
21600                                        None
21601                                    }
21602                                })?;
21603                            pane.update(cx, |pane, cx| {
21604                                pane.activate_item(pane_item_index, true, true, window, cx)
21605                            });
21606                            Some(editor)
21607                        })
21608                        .flatten()
21609                        .unwrap_or_else(|| {
21610                            workspace.open_project_item::<Self>(
21611                                pane.clone(),
21612                                buffer,
21613                                true,
21614                                true,
21615                                window,
21616                                cx,
21617                            )
21618                        });
21619
21620                    editor.update(cx, |editor, cx| {
21621                        let autoscroll = match scroll_offset {
21622                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21623                            None => Autoscroll::newest(),
21624                        };
21625                        let nav_history = editor.nav_history.take();
21626                        editor.change_selections(
21627                            SelectionEffects::scroll(autoscroll),
21628                            window,
21629                            cx,
21630                            |s| {
21631                                s.select_ranges(ranges);
21632                            },
21633                        );
21634                        editor.nav_history = nav_history;
21635                    });
21636                }
21637            })
21638        });
21639    }
21640
21641    // For now, don't allow opening excerpts in buffers that aren't backed by
21642    // regular project files.
21643    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21644        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21645    }
21646
21647    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21648        let snapshot = self.buffer.read(cx).read(cx);
21649        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21650        Some(
21651            ranges
21652                .iter()
21653                .map(move |range| {
21654                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21655                })
21656                .collect(),
21657        )
21658    }
21659
21660    fn selection_replacement_ranges(
21661        &self,
21662        range: Range<OffsetUtf16>,
21663        cx: &mut App,
21664    ) -> Vec<Range<OffsetUtf16>> {
21665        let selections = self
21666            .selections
21667            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21668        let newest_selection = selections
21669            .iter()
21670            .max_by_key(|selection| selection.id)
21671            .unwrap();
21672        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21673        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21674        let snapshot = self.buffer.read(cx).read(cx);
21675        selections
21676            .into_iter()
21677            .map(|mut selection| {
21678                selection.start.0 =
21679                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21680                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21681                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21682                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21683            })
21684            .collect()
21685    }
21686
21687    fn report_editor_event(
21688        &self,
21689        reported_event: ReportEditorEvent,
21690        file_extension: Option<String>,
21691        cx: &App,
21692    ) {
21693        if cfg!(any(test, feature = "test-support")) {
21694            return;
21695        }
21696
21697        let Some(project) = &self.project else { return };
21698
21699        // If None, we are in a file without an extension
21700        let file = self
21701            .buffer
21702            .read(cx)
21703            .as_singleton()
21704            .and_then(|b| b.read(cx).file());
21705        let file_extension = file_extension.or(file
21706            .as_ref()
21707            .and_then(|file| Path::new(file.file_name(cx)).extension())
21708            .and_then(|e| e.to_str())
21709            .map(|a| a.to_string()));
21710
21711        let vim_mode = vim_flavor(cx).is_some();
21712
21713        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21714        let copilot_enabled = edit_predictions_provider
21715            == language::language_settings::EditPredictionProvider::Copilot;
21716        let copilot_enabled_for_language = self
21717            .buffer
21718            .read(cx)
21719            .language_settings(cx)
21720            .show_edit_predictions;
21721
21722        let project = project.read(cx);
21723        let event_type = reported_event.event_type();
21724
21725        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21726            telemetry::event!(
21727                event_type,
21728                type = if auto_saved {"autosave"} else {"manual"},
21729                file_extension,
21730                vim_mode,
21731                copilot_enabled,
21732                copilot_enabled_for_language,
21733                edit_predictions_provider,
21734                is_via_ssh = project.is_via_remote_server(),
21735            );
21736        } else {
21737            telemetry::event!(
21738                event_type,
21739                file_extension,
21740                vim_mode,
21741                copilot_enabled,
21742                copilot_enabled_for_language,
21743                edit_predictions_provider,
21744                is_via_ssh = project.is_via_remote_server(),
21745            );
21746        };
21747    }
21748
21749    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21750    /// with each line being an array of {text, highlight} objects.
21751    fn copy_highlight_json(
21752        &mut self,
21753        _: &CopyHighlightJson,
21754        window: &mut Window,
21755        cx: &mut Context<Self>,
21756    ) {
21757        #[derive(Serialize)]
21758        struct Chunk<'a> {
21759            text: String,
21760            highlight: Option<&'a str>,
21761        }
21762
21763        let snapshot = self.buffer.read(cx).snapshot(cx);
21764        let range = self
21765            .selected_text_range(false, window, cx)
21766            .and_then(|selection| {
21767                if selection.range.is_empty() {
21768                    None
21769                } else {
21770                    Some(
21771                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21772                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21773                    )
21774                }
21775            })
21776            .unwrap_or_else(|| 0..snapshot.len());
21777
21778        let chunks = snapshot.chunks(range, true);
21779        let mut lines = Vec::new();
21780        let mut line: VecDeque<Chunk> = VecDeque::new();
21781
21782        let Some(style) = self.style.as_ref() else {
21783            return;
21784        };
21785
21786        for chunk in chunks {
21787            let highlight = chunk
21788                .syntax_highlight_id
21789                .and_then(|id| id.name(&style.syntax));
21790            let mut chunk_lines = chunk.text.split('\n').peekable();
21791            while let Some(text) = chunk_lines.next() {
21792                let mut merged_with_last_token = false;
21793                if let Some(last_token) = line.back_mut()
21794                    && last_token.highlight == highlight
21795                {
21796                    last_token.text.push_str(text);
21797                    merged_with_last_token = true;
21798                }
21799
21800                if !merged_with_last_token {
21801                    line.push_back(Chunk {
21802                        text: text.into(),
21803                        highlight,
21804                    });
21805                }
21806
21807                if chunk_lines.peek().is_some() {
21808                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21809                        line.pop_front();
21810                    }
21811                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21812                        line.pop_back();
21813                    }
21814
21815                    lines.push(mem::take(&mut line));
21816                }
21817            }
21818        }
21819
21820        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21821            return;
21822        };
21823        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21824    }
21825
21826    pub fn open_context_menu(
21827        &mut self,
21828        _: &OpenContextMenu,
21829        window: &mut Window,
21830        cx: &mut Context<Self>,
21831    ) {
21832        self.request_autoscroll(Autoscroll::newest(), cx);
21833        let position = self
21834            .selections
21835            .newest_display(&self.display_snapshot(cx))
21836            .start;
21837        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21838    }
21839
21840    pub fn replay_insert_event(
21841        &mut self,
21842        text: &str,
21843        relative_utf16_range: Option<Range<isize>>,
21844        window: &mut Window,
21845        cx: &mut Context<Self>,
21846    ) {
21847        if !self.input_enabled {
21848            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21849            return;
21850        }
21851        if let Some(relative_utf16_range) = relative_utf16_range {
21852            let selections = self
21853                .selections
21854                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21855            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21856                let new_ranges = selections.into_iter().map(|range| {
21857                    let start = OffsetUtf16(
21858                        range
21859                            .head()
21860                            .0
21861                            .saturating_add_signed(relative_utf16_range.start),
21862                    );
21863                    let end = OffsetUtf16(
21864                        range
21865                            .head()
21866                            .0
21867                            .saturating_add_signed(relative_utf16_range.end),
21868                    );
21869                    start..end
21870                });
21871                s.select_ranges(new_ranges);
21872            });
21873        }
21874
21875        self.handle_input(text, window, cx);
21876    }
21877
21878    pub fn is_focused(&self, window: &Window) -> bool {
21879        self.focus_handle.is_focused(window)
21880    }
21881
21882    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21883        cx.emit(EditorEvent::Focused);
21884
21885        if let Some(descendant) = self
21886            .last_focused_descendant
21887            .take()
21888            .and_then(|descendant| descendant.upgrade())
21889        {
21890            window.focus(&descendant);
21891        } else {
21892            if let Some(blame) = self.blame.as_ref() {
21893                blame.update(cx, GitBlame::focus)
21894            }
21895
21896            self.blink_manager.update(cx, BlinkManager::enable);
21897            self.show_cursor_names(window, cx);
21898            self.buffer.update(cx, |buffer, cx| {
21899                buffer.finalize_last_transaction(cx);
21900                if self.leader_id.is_none() {
21901                    buffer.set_active_selections(
21902                        &self.selections.disjoint_anchors_arc(),
21903                        self.selections.line_mode(),
21904                        self.cursor_shape,
21905                        cx,
21906                    );
21907                }
21908            });
21909        }
21910    }
21911
21912    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21913        cx.emit(EditorEvent::FocusedIn)
21914    }
21915
21916    fn handle_focus_out(
21917        &mut self,
21918        event: FocusOutEvent,
21919        _window: &mut Window,
21920        cx: &mut Context<Self>,
21921    ) {
21922        if event.blurred != self.focus_handle {
21923            self.last_focused_descendant = Some(event.blurred);
21924        }
21925        self.selection_drag_state = SelectionDragState::None;
21926        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21927    }
21928
21929    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21930        self.blink_manager.update(cx, BlinkManager::disable);
21931        self.buffer
21932            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21933
21934        if let Some(blame) = self.blame.as_ref() {
21935            blame.update(cx, GitBlame::blur)
21936        }
21937        if !self.hover_state.focused(window, cx) {
21938            hide_hover(self, cx);
21939        }
21940        if !self
21941            .context_menu
21942            .borrow()
21943            .as_ref()
21944            .is_some_and(|context_menu| context_menu.focused(window, cx))
21945        {
21946            self.hide_context_menu(window, cx);
21947        }
21948        self.take_active_edit_prediction(cx);
21949        cx.emit(EditorEvent::Blurred);
21950        cx.notify();
21951    }
21952
21953    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21954        let mut pending: String = window
21955            .pending_input_keystrokes()
21956            .into_iter()
21957            .flatten()
21958            .filter_map(|keystroke| {
21959                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21960                    keystroke.key_char.clone()
21961                } else {
21962                    None
21963                }
21964            })
21965            .collect();
21966
21967        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21968            pending = "".to_string();
21969        }
21970
21971        let existing_pending = self
21972            .text_highlights::<PendingInput>(cx)
21973            .map(|(_, ranges)| ranges.to_vec());
21974        if existing_pending.is_none() && pending.is_empty() {
21975            return;
21976        }
21977        let transaction =
21978            self.transact(window, cx, |this, window, cx| {
21979                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21980                let edits = selections
21981                    .iter()
21982                    .map(|selection| (selection.end..selection.end, pending.clone()));
21983                this.edit(edits, cx);
21984                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21985                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21986                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21987                    }));
21988                });
21989                if let Some(existing_ranges) = existing_pending {
21990                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21991                    this.edit(edits, cx);
21992                }
21993            });
21994
21995        let snapshot = self.snapshot(window, cx);
21996        let ranges = self
21997            .selections
21998            .all::<usize>(&snapshot.display_snapshot)
21999            .into_iter()
22000            .map(|selection| {
22001                snapshot.buffer_snapshot().anchor_after(selection.end)
22002                    ..snapshot
22003                        .buffer_snapshot()
22004                        .anchor_before(selection.end + pending.len())
22005            })
22006            .collect();
22007
22008        if pending.is_empty() {
22009            self.clear_highlights::<PendingInput>(cx);
22010        } else {
22011            self.highlight_text::<PendingInput>(
22012                ranges,
22013                HighlightStyle {
22014                    underline: Some(UnderlineStyle {
22015                        thickness: px(1.),
22016                        color: None,
22017                        wavy: false,
22018                    }),
22019                    ..Default::default()
22020                },
22021                cx,
22022            );
22023        }
22024
22025        self.ime_transaction = self.ime_transaction.or(transaction);
22026        if let Some(transaction) = self.ime_transaction {
22027            self.buffer.update(cx, |buffer, cx| {
22028                buffer.group_until_transaction(transaction, cx);
22029            });
22030        }
22031
22032        if self.text_highlights::<PendingInput>(cx).is_none() {
22033            self.ime_transaction.take();
22034        }
22035    }
22036
22037    pub fn register_action_renderer(
22038        &mut self,
22039        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22040    ) -> Subscription {
22041        let id = self.next_editor_action_id.post_inc();
22042        self.editor_actions
22043            .borrow_mut()
22044            .insert(id, Box::new(listener));
22045
22046        let editor_actions = self.editor_actions.clone();
22047        Subscription::new(move || {
22048            editor_actions.borrow_mut().remove(&id);
22049        })
22050    }
22051
22052    pub fn register_action<A: Action>(
22053        &mut self,
22054        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22055    ) -> Subscription {
22056        let id = self.next_editor_action_id.post_inc();
22057        let listener = Arc::new(listener);
22058        self.editor_actions.borrow_mut().insert(
22059            id,
22060            Box::new(move |_, window, _| {
22061                let listener = listener.clone();
22062                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22063                    let action = action.downcast_ref().unwrap();
22064                    if phase == DispatchPhase::Bubble {
22065                        listener(action, window, cx)
22066                    }
22067                })
22068            }),
22069        );
22070
22071        let editor_actions = self.editor_actions.clone();
22072        Subscription::new(move || {
22073            editor_actions.borrow_mut().remove(&id);
22074        })
22075    }
22076
22077    pub fn file_header_size(&self) -> u32 {
22078        FILE_HEADER_HEIGHT
22079    }
22080
22081    pub fn restore(
22082        &mut self,
22083        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22084        window: &mut Window,
22085        cx: &mut Context<Self>,
22086    ) {
22087        let workspace = self.workspace();
22088        let project = self.project();
22089        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22090            let mut tasks = Vec::new();
22091            for (buffer_id, changes) in revert_changes {
22092                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22093                    buffer.update(cx, |buffer, cx| {
22094                        buffer.edit(
22095                            changes
22096                                .into_iter()
22097                                .map(|(range, text)| (range, text.to_string())),
22098                            None,
22099                            cx,
22100                        );
22101                    });
22102
22103                    if let Some(project) =
22104                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22105                    {
22106                        project.update(cx, |project, cx| {
22107                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22108                        })
22109                    }
22110                }
22111            }
22112            tasks
22113        });
22114        cx.spawn_in(window, async move |_, cx| {
22115            for (buffer, task) in save_tasks {
22116                let result = task.await;
22117                if result.is_err() {
22118                    let Some(path) = buffer
22119                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22120                        .ok()
22121                    else {
22122                        continue;
22123                    };
22124                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22125                        let Some(task) = cx
22126                            .update_window_entity(workspace, |workspace, window, cx| {
22127                                workspace
22128                                    .open_path_preview(path, None, false, false, false, window, cx)
22129                            })
22130                            .ok()
22131                        else {
22132                            continue;
22133                        };
22134                        task.await.log_err();
22135                    }
22136                }
22137            }
22138        })
22139        .detach();
22140        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22141            selections.refresh()
22142        });
22143    }
22144
22145    pub fn to_pixel_point(
22146        &self,
22147        source: multi_buffer::Anchor,
22148        editor_snapshot: &EditorSnapshot,
22149        window: &mut Window,
22150    ) -> Option<gpui::Point<Pixels>> {
22151        let source_point = source.to_display_point(editor_snapshot);
22152        self.display_to_pixel_point(source_point, editor_snapshot, window)
22153    }
22154
22155    pub fn display_to_pixel_point(
22156        &self,
22157        source: DisplayPoint,
22158        editor_snapshot: &EditorSnapshot,
22159        window: &mut Window,
22160    ) -> Option<gpui::Point<Pixels>> {
22161        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22162        let text_layout_details = self.text_layout_details(window);
22163        let scroll_top = text_layout_details
22164            .scroll_anchor
22165            .scroll_position(editor_snapshot)
22166            .y;
22167
22168        if source.row().as_f64() < scroll_top.floor() {
22169            return None;
22170        }
22171        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22172        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22173        Some(gpui::Point::new(source_x, source_y))
22174    }
22175
22176    pub fn has_visible_completions_menu(&self) -> bool {
22177        !self.edit_prediction_preview_is_active()
22178            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22179                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22180            })
22181    }
22182
22183    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22184        if self.mode.is_minimap() {
22185            return;
22186        }
22187        self.addons
22188            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22189    }
22190
22191    pub fn unregister_addon<T: Addon>(&mut self) {
22192        self.addons.remove(&std::any::TypeId::of::<T>());
22193    }
22194
22195    pub fn addon<T: Addon>(&self) -> Option<&T> {
22196        let type_id = std::any::TypeId::of::<T>();
22197        self.addons
22198            .get(&type_id)
22199            .and_then(|item| item.to_any().downcast_ref::<T>())
22200    }
22201
22202    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22203        let type_id = std::any::TypeId::of::<T>();
22204        self.addons
22205            .get_mut(&type_id)
22206            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22207    }
22208
22209    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22210        let text_layout_details = self.text_layout_details(window);
22211        let style = &text_layout_details.editor_style;
22212        let font_id = window.text_system().resolve_font(&style.text.font());
22213        let font_size = style.text.font_size.to_pixels(window.rem_size());
22214        let line_height = style.text.line_height_in_pixels(window.rem_size());
22215        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22216        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22217
22218        CharacterDimensions {
22219            em_width,
22220            em_advance,
22221            line_height,
22222        }
22223    }
22224
22225    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22226        self.load_diff_task.clone()
22227    }
22228
22229    fn read_metadata_from_db(
22230        &mut self,
22231        item_id: u64,
22232        workspace_id: WorkspaceId,
22233        window: &mut Window,
22234        cx: &mut Context<Editor>,
22235    ) {
22236        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22237            && !self.mode.is_minimap()
22238            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22239        {
22240            let buffer_snapshot = OnceCell::new();
22241
22242            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22243                && !folds.is_empty()
22244            {
22245                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22246                self.fold_ranges(
22247                    folds
22248                        .into_iter()
22249                        .map(|(start, end)| {
22250                            snapshot.clip_offset(start, Bias::Left)
22251                                ..snapshot.clip_offset(end, Bias::Right)
22252                        })
22253                        .collect(),
22254                    false,
22255                    window,
22256                    cx,
22257                );
22258            }
22259
22260            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22261                && !selections.is_empty()
22262            {
22263                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22264                // skip adding the initial selection to selection history
22265                self.selection_history.mode = SelectionHistoryMode::Skipping;
22266                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22267                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22268                        snapshot.clip_offset(start, Bias::Left)
22269                            ..snapshot.clip_offset(end, Bias::Right)
22270                    }));
22271                });
22272                self.selection_history.mode = SelectionHistoryMode::Normal;
22273            };
22274        }
22275
22276        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22277    }
22278
22279    fn update_lsp_data(
22280        &mut self,
22281        for_buffer: Option<BufferId>,
22282        window: &mut Window,
22283        cx: &mut Context<'_, Self>,
22284    ) {
22285        self.pull_diagnostics(for_buffer, window, cx);
22286        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22287    }
22288
22289    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22290        if self.ignore_lsp_data() {
22291            return;
22292        }
22293        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22294            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22295        }
22296    }
22297
22298    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22299        if self.ignore_lsp_data() {
22300            return;
22301        }
22302
22303        if !self.registered_buffers.contains_key(&buffer_id)
22304            && let Some(project) = self.project.as_ref()
22305        {
22306            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22307                project.update(cx, |project, cx| {
22308                    self.registered_buffers.insert(
22309                        buffer_id,
22310                        project.register_buffer_with_language_servers(&buffer, cx),
22311                    );
22312                });
22313            } else {
22314                self.registered_buffers.remove(&buffer_id);
22315            }
22316        }
22317    }
22318
22319    fn ignore_lsp_data(&self) -> bool {
22320        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22321        // skip any LSP updates for it.
22322        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22323    }
22324}
22325
22326fn edit_for_markdown_paste<'a>(
22327    buffer: &MultiBufferSnapshot,
22328    range: Range<usize>,
22329    to_insert: &'a str,
22330    url: Option<url::Url>,
22331) -> (Range<usize>, Cow<'a, str>) {
22332    if url.is_none() {
22333        return (range, Cow::Borrowed(to_insert));
22334    };
22335
22336    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22337
22338    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22339        Cow::Borrowed(to_insert)
22340    } else {
22341        Cow::Owned(format!("[{old_text}]({to_insert})"))
22342    };
22343    (range, new_text)
22344}
22345
22346#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22347pub enum VimFlavor {
22348    Vim,
22349    Helix,
22350}
22351
22352pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22353    if vim_mode_setting::HelixModeSetting::try_get(cx)
22354        .map(|helix_mode| helix_mode.0)
22355        .unwrap_or(false)
22356    {
22357        Some(VimFlavor::Helix)
22358    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22359        .map(|vim_mode| vim_mode.0)
22360        .unwrap_or(false)
22361    {
22362        Some(VimFlavor::Vim)
22363    } else {
22364        None // neither vim nor helix mode
22365    }
22366}
22367
22368fn process_completion_for_edit(
22369    completion: &Completion,
22370    intent: CompletionIntent,
22371    buffer: &Entity<Buffer>,
22372    cursor_position: &text::Anchor,
22373    cx: &mut Context<Editor>,
22374) -> CompletionEdit {
22375    let buffer = buffer.read(cx);
22376    let buffer_snapshot = buffer.snapshot();
22377    let (snippet, new_text) = if completion.is_snippet() {
22378        let mut snippet_source = completion.new_text.clone();
22379        // Workaround for typescript language server issues so that methods don't expand within
22380        // strings and functions with type expressions. The previous point is used because the query
22381        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22382        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22383        let previous_point = if previous_point.column > 0 {
22384            cursor_position.to_previous_offset(&buffer_snapshot)
22385        } else {
22386            cursor_position.to_offset(&buffer_snapshot)
22387        };
22388        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22389            && scope.prefers_label_for_snippet_in_completion()
22390            && let Some(label) = completion.label()
22391            && matches!(
22392                completion.kind(),
22393                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22394            )
22395        {
22396            snippet_source = label;
22397        }
22398        match Snippet::parse(&snippet_source).log_err() {
22399            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22400            None => (None, completion.new_text.clone()),
22401        }
22402    } else {
22403        (None, completion.new_text.clone())
22404    };
22405
22406    let mut range_to_replace = {
22407        let replace_range = &completion.replace_range;
22408        if let CompletionSource::Lsp {
22409            insert_range: Some(insert_range),
22410            ..
22411        } = &completion.source
22412        {
22413            debug_assert_eq!(
22414                insert_range.start, replace_range.start,
22415                "insert_range and replace_range should start at the same position"
22416            );
22417            debug_assert!(
22418                insert_range
22419                    .start
22420                    .cmp(cursor_position, &buffer_snapshot)
22421                    .is_le(),
22422                "insert_range should start before or at cursor position"
22423            );
22424            debug_assert!(
22425                replace_range
22426                    .start
22427                    .cmp(cursor_position, &buffer_snapshot)
22428                    .is_le(),
22429                "replace_range should start before or at cursor position"
22430            );
22431
22432            let should_replace = match intent {
22433                CompletionIntent::CompleteWithInsert => false,
22434                CompletionIntent::CompleteWithReplace => true,
22435                CompletionIntent::Complete | CompletionIntent::Compose => {
22436                    let insert_mode =
22437                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22438                            .completions
22439                            .lsp_insert_mode;
22440                    match insert_mode {
22441                        LspInsertMode::Insert => false,
22442                        LspInsertMode::Replace => true,
22443                        LspInsertMode::ReplaceSubsequence => {
22444                            let mut text_to_replace = buffer.chars_for_range(
22445                                buffer.anchor_before(replace_range.start)
22446                                    ..buffer.anchor_after(replace_range.end),
22447                            );
22448                            let mut current_needle = text_to_replace.next();
22449                            for haystack_ch in completion.label.text.chars() {
22450                                if let Some(needle_ch) = current_needle
22451                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22452                                {
22453                                    current_needle = text_to_replace.next();
22454                                }
22455                            }
22456                            current_needle.is_none()
22457                        }
22458                        LspInsertMode::ReplaceSuffix => {
22459                            if replace_range
22460                                .end
22461                                .cmp(cursor_position, &buffer_snapshot)
22462                                .is_gt()
22463                            {
22464                                let range_after_cursor = *cursor_position..replace_range.end;
22465                                let text_after_cursor = buffer
22466                                    .text_for_range(
22467                                        buffer.anchor_before(range_after_cursor.start)
22468                                            ..buffer.anchor_after(range_after_cursor.end),
22469                                    )
22470                                    .collect::<String>()
22471                                    .to_ascii_lowercase();
22472                                completion
22473                                    .label
22474                                    .text
22475                                    .to_ascii_lowercase()
22476                                    .ends_with(&text_after_cursor)
22477                            } else {
22478                                true
22479                            }
22480                        }
22481                    }
22482                }
22483            };
22484
22485            if should_replace {
22486                replace_range.clone()
22487            } else {
22488                insert_range.clone()
22489            }
22490        } else {
22491            replace_range.clone()
22492        }
22493    };
22494
22495    if range_to_replace
22496        .end
22497        .cmp(cursor_position, &buffer_snapshot)
22498        .is_lt()
22499    {
22500        range_to_replace.end = *cursor_position;
22501    }
22502
22503    CompletionEdit {
22504        new_text,
22505        replace_range: range_to_replace.to_offset(buffer),
22506        snippet,
22507    }
22508}
22509
22510struct CompletionEdit {
22511    new_text: String,
22512    replace_range: Range<usize>,
22513    snippet: Option<Snippet>,
22514}
22515
22516fn insert_extra_newline_brackets(
22517    buffer: &MultiBufferSnapshot,
22518    range: Range<usize>,
22519    language: &language::LanguageScope,
22520) -> bool {
22521    let leading_whitespace_len = buffer
22522        .reversed_chars_at(range.start)
22523        .take_while(|c| c.is_whitespace() && *c != '\n')
22524        .map(|c| c.len_utf8())
22525        .sum::<usize>();
22526    let trailing_whitespace_len = buffer
22527        .chars_at(range.end)
22528        .take_while(|c| c.is_whitespace() && *c != '\n')
22529        .map(|c| c.len_utf8())
22530        .sum::<usize>();
22531    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22532
22533    language.brackets().any(|(pair, enabled)| {
22534        let pair_start = pair.start.trim_end();
22535        let pair_end = pair.end.trim_start();
22536
22537        enabled
22538            && pair.newline
22539            && buffer.contains_str_at(range.end, pair_end)
22540            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22541    })
22542}
22543
22544fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22545    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22546        [(buffer, range, _)] => (*buffer, range.clone()),
22547        _ => return false,
22548    };
22549    let pair = {
22550        let mut result: Option<BracketMatch> = None;
22551
22552        for pair in buffer
22553            .all_bracket_ranges(range.clone())
22554            .filter(move |pair| {
22555                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22556            })
22557        {
22558            let len = pair.close_range.end - pair.open_range.start;
22559
22560            if let Some(existing) = &result {
22561                let existing_len = existing.close_range.end - existing.open_range.start;
22562                if len > existing_len {
22563                    continue;
22564                }
22565            }
22566
22567            result = Some(pair);
22568        }
22569
22570        result
22571    };
22572    let Some(pair) = pair else {
22573        return false;
22574    };
22575    pair.newline_only
22576        && buffer
22577            .chars_for_range(pair.open_range.end..range.start)
22578            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22579            .all(|c| c.is_whitespace() && c != '\n')
22580}
22581
22582fn update_uncommitted_diff_for_buffer(
22583    editor: Entity<Editor>,
22584    project: &Entity<Project>,
22585    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22586    buffer: Entity<MultiBuffer>,
22587    cx: &mut App,
22588) -> Task<()> {
22589    let mut tasks = Vec::new();
22590    project.update(cx, |project, cx| {
22591        for buffer in buffers {
22592            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22593                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22594            }
22595        }
22596    });
22597    cx.spawn(async move |cx| {
22598        let diffs = future::join_all(tasks).await;
22599        if editor
22600            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22601            .unwrap_or(false)
22602        {
22603            return;
22604        }
22605
22606        buffer
22607            .update(cx, |buffer, cx| {
22608                for diff in diffs.into_iter().flatten() {
22609                    buffer.add_diff(diff, cx);
22610                }
22611            })
22612            .ok();
22613    })
22614}
22615
22616fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22617    let tab_size = tab_size.get() as usize;
22618    let mut width = offset;
22619
22620    for ch in text.chars() {
22621        width += if ch == '\t' {
22622            tab_size - (width % tab_size)
22623        } else {
22624            1
22625        };
22626    }
22627
22628    width - offset
22629}
22630
22631#[cfg(test)]
22632mod tests {
22633    use super::*;
22634
22635    #[test]
22636    fn test_string_size_with_expanded_tabs() {
22637        let nz = |val| NonZeroU32::new(val).unwrap();
22638        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22639        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22640        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22641        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22642        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22643        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22644        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22645        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22646    }
22647}
22648
22649/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22650struct WordBreakingTokenizer<'a> {
22651    input: &'a str,
22652}
22653
22654impl<'a> WordBreakingTokenizer<'a> {
22655    fn new(input: &'a str) -> Self {
22656        Self { input }
22657    }
22658}
22659
22660fn is_char_ideographic(ch: char) -> bool {
22661    use unicode_script::Script::*;
22662    use unicode_script::UnicodeScript;
22663    matches!(ch.script(), Han | Tangut | Yi)
22664}
22665
22666fn is_grapheme_ideographic(text: &str) -> bool {
22667    text.chars().any(is_char_ideographic)
22668}
22669
22670fn is_grapheme_whitespace(text: &str) -> bool {
22671    text.chars().any(|x| x.is_whitespace())
22672}
22673
22674fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22675    text.chars()
22676        .next()
22677        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22678}
22679
22680#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22681enum WordBreakToken<'a> {
22682    Word { token: &'a str, grapheme_len: usize },
22683    InlineWhitespace { token: &'a str, grapheme_len: usize },
22684    Newline,
22685}
22686
22687impl<'a> Iterator for WordBreakingTokenizer<'a> {
22688    /// Yields a span, the count of graphemes in the token, and whether it was
22689    /// whitespace. Note that it also breaks at word boundaries.
22690    type Item = WordBreakToken<'a>;
22691
22692    fn next(&mut self) -> Option<Self::Item> {
22693        use unicode_segmentation::UnicodeSegmentation;
22694        if self.input.is_empty() {
22695            return None;
22696        }
22697
22698        let mut iter = self.input.graphemes(true).peekable();
22699        let mut offset = 0;
22700        let mut grapheme_len = 0;
22701        if let Some(first_grapheme) = iter.next() {
22702            let is_newline = first_grapheme == "\n";
22703            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22704            offset += first_grapheme.len();
22705            grapheme_len += 1;
22706            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22707                if let Some(grapheme) = iter.peek().copied()
22708                    && should_stay_with_preceding_ideograph(grapheme)
22709                {
22710                    offset += grapheme.len();
22711                    grapheme_len += 1;
22712                }
22713            } else {
22714                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22715                let mut next_word_bound = words.peek().copied();
22716                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22717                    next_word_bound = words.next();
22718                }
22719                while let Some(grapheme) = iter.peek().copied() {
22720                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22721                        break;
22722                    };
22723                    if is_grapheme_whitespace(grapheme) != is_whitespace
22724                        || (grapheme == "\n") != is_newline
22725                    {
22726                        break;
22727                    };
22728                    offset += grapheme.len();
22729                    grapheme_len += 1;
22730                    iter.next();
22731                }
22732            }
22733            let token = &self.input[..offset];
22734            self.input = &self.input[offset..];
22735            if token == "\n" {
22736                Some(WordBreakToken::Newline)
22737            } else if is_whitespace {
22738                Some(WordBreakToken::InlineWhitespace {
22739                    token,
22740                    grapheme_len,
22741                })
22742            } else {
22743                Some(WordBreakToken::Word {
22744                    token,
22745                    grapheme_len,
22746                })
22747            }
22748        } else {
22749            None
22750        }
22751    }
22752}
22753
22754#[test]
22755fn test_word_breaking_tokenizer() {
22756    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22757        ("", &[]),
22758        ("  ", &[whitespace("  ", 2)]),
22759        ("Ʒ", &[word("Ʒ", 1)]),
22760        ("Ǽ", &[word("Ǽ", 1)]),
22761        ("", &[word("", 1)]),
22762        ("⋑⋑", &[word("⋑⋑", 2)]),
22763        (
22764            "原理,进而",
22765            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22766        ),
22767        (
22768            "hello world",
22769            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22770        ),
22771        (
22772            "hello, world",
22773            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22774        ),
22775        (
22776            "  hello world",
22777            &[
22778                whitespace("  ", 2),
22779                word("hello", 5),
22780                whitespace(" ", 1),
22781                word("world", 5),
22782            ],
22783        ),
22784        (
22785            "这是什么 \n 钢笔",
22786            &[
22787                word("", 1),
22788                word("", 1),
22789                word("", 1),
22790                word("", 1),
22791                whitespace(" ", 1),
22792                newline(),
22793                whitespace(" ", 1),
22794                word("", 1),
22795                word("", 1),
22796            ],
22797        ),
22798        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22799    ];
22800
22801    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22802        WordBreakToken::Word {
22803            token,
22804            grapheme_len,
22805        }
22806    }
22807
22808    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22809        WordBreakToken::InlineWhitespace {
22810            token,
22811            grapheme_len,
22812        }
22813    }
22814
22815    fn newline() -> WordBreakToken<'static> {
22816        WordBreakToken::Newline
22817    }
22818
22819    for (input, result) in tests {
22820        assert_eq!(
22821            WordBreakingTokenizer::new(input)
22822                .collect::<Vec<_>>()
22823                .as_slice(),
22824            *result,
22825        );
22826    }
22827}
22828
22829fn wrap_with_prefix(
22830    first_line_prefix: String,
22831    subsequent_lines_prefix: String,
22832    unwrapped_text: String,
22833    wrap_column: usize,
22834    tab_size: NonZeroU32,
22835    preserve_existing_whitespace: bool,
22836) -> String {
22837    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22838    let subsequent_lines_prefix_len =
22839        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22840    let mut wrapped_text = String::new();
22841    let mut current_line = first_line_prefix;
22842    let mut is_first_line = true;
22843
22844    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22845    let mut current_line_len = first_line_prefix_len;
22846    let mut in_whitespace = false;
22847    for token in tokenizer {
22848        let have_preceding_whitespace = in_whitespace;
22849        match token {
22850            WordBreakToken::Word {
22851                token,
22852                grapheme_len,
22853            } => {
22854                in_whitespace = false;
22855                let current_prefix_len = if is_first_line {
22856                    first_line_prefix_len
22857                } else {
22858                    subsequent_lines_prefix_len
22859                };
22860                if current_line_len + grapheme_len > wrap_column
22861                    && current_line_len != current_prefix_len
22862                {
22863                    wrapped_text.push_str(current_line.trim_end());
22864                    wrapped_text.push('\n');
22865                    is_first_line = false;
22866                    current_line = subsequent_lines_prefix.clone();
22867                    current_line_len = subsequent_lines_prefix_len;
22868                }
22869                current_line.push_str(token);
22870                current_line_len += grapheme_len;
22871            }
22872            WordBreakToken::InlineWhitespace {
22873                mut token,
22874                mut grapheme_len,
22875            } => {
22876                in_whitespace = true;
22877                if have_preceding_whitespace && !preserve_existing_whitespace {
22878                    continue;
22879                }
22880                if !preserve_existing_whitespace {
22881                    // Keep a single whitespace grapheme as-is
22882                    if let Some(first) =
22883                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22884                    {
22885                        token = first;
22886                    } else {
22887                        token = " ";
22888                    }
22889                    grapheme_len = 1;
22890                }
22891                let current_prefix_len = if is_first_line {
22892                    first_line_prefix_len
22893                } else {
22894                    subsequent_lines_prefix_len
22895                };
22896                if current_line_len + grapheme_len > wrap_column {
22897                    wrapped_text.push_str(current_line.trim_end());
22898                    wrapped_text.push('\n');
22899                    is_first_line = false;
22900                    current_line = subsequent_lines_prefix.clone();
22901                    current_line_len = subsequent_lines_prefix_len;
22902                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22903                    current_line.push_str(token);
22904                    current_line_len += grapheme_len;
22905                }
22906            }
22907            WordBreakToken::Newline => {
22908                in_whitespace = true;
22909                let current_prefix_len = if is_first_line {
22910                    first_line_prefix_len
22911                } else {
22912                    subsequent_lines_prefix_len
22913                };
22914                if preserve_existing_whitespace {
22915                    wrapped_text.push_str(current_line.trim_end());
22916                    wrapped_text.push('\n');
22917                    is_first_line = false;
22918                    current_line = subsequent_lines_prefix.clone();
22919                    current_line_len = subsequent_lines_prefix_len;
22920                } else if have_preceding_whitespace {
22921                    continue;
22922                } else if current_line_len + 1 > wrap_column
22923                    && current_line_len != current_prefix_len
22924                {
22925                    wrapped_text.push_str(current_line.trim_end());
22926                    wrapped_text.push('\n');
22927                    is_first_line = false;
22928                    current_line = subsequent_lines_prefix.clone();
22929                    current_line_len = subsequent_lines_prefix_len;
22930                } else if current_line_len != current_prefix_len {
22931                    current_line.push(' ');
22932                    current_line_len += 1;
22933                }
22934            }
22935        }
22936    }
22937
22938    if !current_line.is_empty() {
22939        wrapped_text.push_str(&current_line);
22940    }
22941    wrapped_text
22942}
22943
22944#[test]
22945fn test_wrap_with_prefix() {
22946    assert_eq!(
22947        wrap_with_prefix(
22948            "# ".to_string(),
22949            "# ".to_string(),
22950            "abcdefg".to_string(),
22951            4,
22952            NonZeroU32::new(4).unwrap(),
22953            false,
22954        ),
22955        "# abcdefg"
22956    );
22957    assert_eq!(
22958        wrap_with_prefix(
22959            "".to_string(),
22960            "".to_string(),
22961            "\thello world".to_string(),
22962            8,
22963            NonZeroU32::new(4).unwrap(),
22964            false,
22965        ),
22966        "hello\nworld"
22967    );
22968    assert_eq!(
22969        wrap_with_prefix(
22970            "// ".to_string(),
22971            "// ".to_string(),
22972            "xx \nyy zz aa bb cc".to_string(),
22973            12,
22974            NonZeroU32::new(4).unwrap(),
22975            false,
22976        ),
22977        "// xx yy zz\n// aa bb cc"
22978    );
22979    assert_eq!(
22980        wrap_with_prefix(
22981            String::new(),
22982            String::new(),
22983            "这是什么 \n 钢笔".to_string(),
22984            3,
22985            NonZeroU32::new(4).unwrap(),
22986            false,
22987        ),
22988        "这是什\n么 钢\n"
22989    );
22990    assert_eq!(
22991        wrap_with_prefix(
22992            String::new(),
22993            String::new(),
22994            format!("foo{}bar", '\u{2009}'), // thin space
22995            80,
22996            NonZeroU32::new(4).unwrap(),
22997            false,
22998        ),
22999        format!("foo{}bar", '\u{2009}')
23000    );
23001}
23002
23003pub trait CollaborationHub {
23004    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23005    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23006    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23007}
23008
23009impl CollaborationHub for Entity<Project> {
23010    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23011        self.read(cx).collaborators()
23012    }
23013
23014    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23015        self.read(cx).user_store().read(cx).participant_indices()
23016    }
23017
23018    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23019        let this = self.read(cx);
23020        let user_ids = this.collaborators().values().map(|c| c.user_id);
23021        this.user_store().read(cx).participant_names(user_ids, cx)
23022    }
23023}
23024
23025pub trait SemanticsProvider {
23026    fn hover(
23027        &self,
23028        buffer: &Entity<Buffer>,
23029        position: text::Anchor,
23030        cx: &mut App,
23031    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23032
23033    fn inline_values(
23034        &self,
23035        buffer_handle: Entity<Buffer>,
23036        range: Range<text::Anchor>,
23037        cx: &mut App,
23038    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23039
23040    fn applicable_inlay_chunks(
23041        &self,
23042        buffer: &Entity<Buffer>,
23043        ranges: &[Range<text::Anchor>],
23044        cx: &mut App,
23045    ) -> Vec<Range<BufferRow>>;
23046
23047    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23048
23049    fn inlay_hints(
23050        &self,
23051        invalidate: InvalidationStrategy,
23052        buffer: Entity<Buffer>,
23053        ranges: Vec<Range<text::Anchor>>,
23054        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23055        cx: &mut App,
23056    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23057
23058    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23059
23060    fn document_highlights(
23061        &self,
23062        buffer: &Entity<Buffer>,
23063        position: text::Anchor,
23064        cx: &mut App,
23065    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23066
23067    fn definitions(
23068        &self,
23069        buffer: &Entity<Buffer>,
23070        position: text::Anchor,
23071        kind: GotoDefinitionKind,
23072        cx: &mut App,
23073    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23074
23075    fn range_for_rename(
23076        &self,
23077        buffer: &Entity<Buffer>,
23078        position: text::Anchor,
23079        cx: &mut App,
23080    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23081
23082    fn perform_rename(
23083        &self,
23084        buffer: &Entity<Buffer>,
23085        position: text::Anchor,
23086        new_name: String,
23087        cx: &mut App,
23088    ) -> Option<Task<Result<ProjectTransaction>>>;
23089}
23090
23091pub trait CompletionProvider {
23092    fn completions(
23093        &self,
23094        excerpt_id: ExcerptId,
23095        buffer: &Entity<Buffer>,
23096        buffer_position: text::Anchor,
23097        trigger: CompletionContext,
23098        window: &mut Window,
23099        cx: &mut Context<Editor>,
23100    ) -> Task<Result<Vec<CompletionResponse>>>;
23101
23102    fn resolve_completions(
23103        &self,
23104        _buffer: Entity<Buffer>,
23105        _completion_indices: Vec<usize>,
23106        _completions: Rc<RefCell<Box<[Completion]>>>,
23107        _cx: &mut Context<Editor>,
23108    ) -> Task<Result<bool>> {
23109        Task::ready(Ok(false))
23110    }
23111
23112    fn apply_additional_edits_for_completion(
23113        &self,
23114        _buffer: Entity<Buffer>,
23115        _completions: Rc<RefCell<Box<[Completion]>>>,
23116        _completion_index: usize,
23117        _push_to_history: bool,
23118        _cx: &mut Context<Editor>,
23119    ) -> Task<Result<Option<language::Transaction>>> {
23120        Task::ready(Ok(None))
23121    }
23122
23123    fn is_completion_trigger(
23124        &self,
23125        buffer: &Entity<Buffer>,
23126        position: language::Anchor,
23127        text: &str,
23128        trigger_in_words: bool,
23129        menu_is_open: bool,
23130        cx: &mut Context<Editor>,
23131    ) -> bool;
23132
23133    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23134
23135    fn sort_completions(&self) -> bool {
23136        true
23137    }
23138
23139    fn filter_completions(&self) -> bool {
23140        true
23141    }
23142
23143    fn show_snippets(&self) -> bool {
23144        false
23145    }
23146}
23147
23148pub trait CodeActionProvider {
23149    fn id(&self) -> Arc<str>;
23150
23151    fn code_actions(
23152        &self,
23153        buffer: &Entity<Buffer>,
23154        range: Range<text::Anchor>,
23155        window: &mut Window,
23156        cx: &mut App,
23157    ) -> Task<Result<Vec<CodeAction>>>;
23158
23159    fn apply_code_action(
23160        &self,
23161        buffer_handle: Entity<Buffer>,
23162        action: CodeAction,
23163        excerpt_id: ExcerptId,
23164        push_to_history: bool,
23165        window: &mut Window,
23166        cx: &mut App,
23167    ) -> Task<Result<ProjectTransaction>>;
23168}
23169
23170impl CodeActionProvider for Entity<Project> {
23171    fn id(&self) -> Arc<str> {
23172        "project".into()
23173    }
23174
23175    fn code_actions(
23176        &self,
23177        buffer: &Entity<Buffer>,
23178        range: Range<text::Anchor>,
23179        _window: &mut Window,
23180        cx: &mut App,
23181    ) -> Task<Result<Vec<CodeAction>>> {
23182        self.update(cx, |project, cx| {
23183            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23184            let code_actions = project.code_actions(buffer, range, None, cx);
23185            cx.background_spawn(async move {
23186                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23187                Ok(code_lens_actions
23188                    .context("code lens fetch")?
23189                    .into_iter()
23190                    .flatten()
23191                    .chain(
23192                        code_actions
23193                            .context("code action fetch")?
23194                            .into_iter()
23195                            .flatten(),
23196                    )
23197                    .collect())
23198            })
23199        })
23200    }
23201
23202    fn apply_code_action(
23203        &self,
23204        buffer_handle: Entity<Buffer>,
23205        action: CodeAction,
23206        _excerpt_id: ExcerptId,
23207        push_to_history: bool,
23208        _window: &mut Window,
23209        cx: &mut App,
23210    ) -> Task<Result<ProjectTransaction>> {
23211        self.update(cx, |project, cx| {
23212            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23213        })
23214    }
23215}
23216
23217fn snippet_completions(
23218    project: &Project,
23219    buffer: &Entity<Buffer>,
23220    buffer_anchor: text::Anchor,
23221    classifier: CharClassifier,
23222    cx: &mut App,
23223) -> Task<Result<CompletionResponse>> {
23224    let languages = buffer.read(cx).languages_at(buffer_anchor);
23225    let snippet_store = project.snippets().read(cx);
23226
23227    let scopes: Vec<_> = languages
23228        .iter()
23229        .filter_map(|language| {
23230            let language_name = language.lsp_id();
23231            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23232
23233            if snippets.is_empty() {
23234                None
23235            } else {
23236                Some((language.default_scope(), snippets))
23237            }
23238        })
23239        .collect();
23240
23241    if scopes.is_empty() {
23242        return Task::ready(Ok(CompletionResponse {
23243            completions: vec![],
23244            display_options: CompletionDisplayOptions::default(),
23245            is_incomplete: false,
23246        }));
23247    }
23248
23249    let snapshot = buffer.read(cx).text_snapshot();
23250    let executor = cx.background_executor().clone();
23251
23252    cx.background_spawn(async move {
23253        let is_word_char = |c| classifier.is_word(c);
23254
23255        let mut is_incomplete = false;
23256        let mut completions: Vec<Completion> = Vec::new();
23257
23258        const MAX_PREFIX_LEN: usize = 128;
23259        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23260        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23261        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23262
23263        let max_buffer_window: String = snapshot
23264            .text_for_range(window_start..buffer_offset)
23265            .collect();
23266
23267        if max_buffer_window.is_empty() {
23268            return Ok(CompletionResponse {
23269                completions: vec![],
23270                display_options: CompletionDisplayOptions::default(),
23271                is_incomplete: true,
23272            });
23273        }
23274
23275        for (_scope, snippets) in scopes.into_iter() {
23276            // Sort snippets by word count to match longer snippet prefixes first.
23277            let mut sorted_snippet_candidates = snippets
23278                .iter()
23279                .enumerate()
23280                .flat_map(|(snippet_ix, snippet)| {
23281                    snippet
23282                        .prefix
23283                        .iter()
23284                        .enumerate()
23285                        .map(move |(prefix_ix, prefix)| {
23286                            let word_count =
23287                                snippet_candidate_suffixes(prefix, is_word_char).count();
23288                            ((snippet_ix, prefix_ix), prefix, word_count)
23289                        })
23290                })
23291                .collect_vec();
23292            sorted_snippet_candidates
23293                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23294
23295            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23296
23297            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23298                .take(
23299                    sorted_snippet_candidates
23300                        .first()
23301                        .map(|(_, _, word_count)| *word_count)
23302                        .unwrap_or_default(),
23303                )
23304                .collect_vec();
23305
23306            const MAX_RESULTS: usize = 100;
23307            // Each match also remembers how many characters from the buffer it consumed
23308            let mut matches: Vec<(StringMatch, usize)> = vec![];
23309
23310            let mut snippet_list_cutoff_index = 0;
23311            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23312                let word_count = buffer_index + 1;
23313                // Increase `snippet_list_cutoff_index` until we have all of the
23314                // snippets with sufficiently many words.
23315                while sorted_snippet_candidates
23316                    .get(snippet_list_cutoff_index)
23317                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23318                        *snippet_word_count >= word_count
23319                    })
23320                {
23321                    snippet_list_cutoff_index += 1;
23322                }
23323
23324                // Take only the candidates with at least `word_count` many words
23325                let snippet_candidates_at_word_len =
23326                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23327
23328                let candidates = snippet_candidates_at_word_len
23329                    .iter()
23330                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23331                    .enumerate() // index in `sorted_snippet_candidates`
23332                    // First char must match
23333                    .filter(|(_ix, prefix)| {
23334                        itertools::equal(
23335                            prefix
23336                                .chars()
23337                                .next()
23338                                .into_iter()
23339                                .flat_map(|c| c.to_lowercase()),
23340                            buffer_window
23341                                .chars()
23342                                .next()
23343                                .into_iter()
23344                                .flat_map(|c| c.to_lowercase()),
23345                        )
23346                    })
23347                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23348                    .collect::<Vec<StringMatchCandidate>>();
23349
23350                matches.extend(
23351                    fuzzy::match_strings(
23352                        &candidates,
23353                        &buffer_window,
23354                        buffer_window.chars().any(|c| c.is_uppercase()),
23355                        true,
23356                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23357                        &Default::default(),
23358                        executor.clone(),
23359                    )
23360                    .await
23361                    .into_iter()
23362                    .map(|string_match| (string_match, buffer_window.len())),
23363                );
23364
23365                if matches.len() >= MAX_RESULTS {
23366                    break;
23367                }
23368            }
23369
23370            let to_lsp = |point: &text::Anchor| {
23371                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23372                point_to_lsp(end)
23373            };
23374            let lsp_end = to_lsp(&buffer_anchor);
23375
23376            if matches.len() >= MAX_RESULTS {
23377                is_incomplete = true;
23378            }
23379
23380            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23381                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23382                    sorted_snippet_candidates[string_match.candidate_id];
23383                let snippet = &snippets[snippet_index];
23384                let start = buffer_offset - buffer_window_len;
23385                let start = snapshot.anchor_before(start);
23386                let range = start..buffer_anchor;
23387                let lsp_start = to_lsp(&start);
23388                let lsp_range = lsp::Range {
23389                    start: lsp_start,
23390                    end: lsp_end,
23391                };
23392                Completion {
23393                    replace_range: range,
23394                    new_text: snippet.body.clone(),
23395                    source: CompletionSource::Lsp {
23396                        insert_range: None,
23397                        server_id: LanguageServerId(usize::MAX),
23398                        resolved: true,
23399                        lsp_completion: Box::new(lsp::CompletionItem {
23400                            label: snippet.prefix.first().unwrap().clone(),
23401                            kind: Some(CompletionItemKind::SNIPPET),
23402                            label_details: snippet.description.as_ref().map(|description| {
23403                                lsp::CompletionItemLabelDetails {
23404                                    detail: Some(description.clone()),
23405                                    description: None,
23406                                }
23407                            }),
23408                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23409                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23410                                lsp::InsertReplaceEdit {
23411                                    new_text: snippet.body.clone(),
23412                                    insert: lsp_range,
23413                                    replace: lsp_range,
23414                                },
23415                            )),
23416                            filter_text: Some(snippet.body.clone()),
23417                            sort_text: Some(char::MAX.to_string()),
23418                            ..lsp::CompletionItem::default()
23419                        }),
23420                        lsp_defaults: None,
23421                    },
23422                    label: CodeLabel {
23423                        text: matching_prefix.clone(),
23424                        runs: Vec::new(),
23425                        filter_range: 0..matching_prefix.len(),
23426                    },
23427                    icon_path: None,
23428                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23429                        single_line: snippet.name.clone().into(),
23430                        plain_text: snippet
23431                            .description
23432                            .clone()
23433                            .map(|description| description.into()),
23434                    }),
23435                    insert_text_mode: None,
23436                    confirm: None,
23437                    match_start: Some(start),
23438                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23439                }
23440            }));
23441        }
23442
23443        Ok(CompletionResponse {
23444            completions,
23445            display_options: CompletionDisplayOptions::default(),
23446            is_incomplete,
23447        })
23448    })
23449}
23450
23451impl CompletionProvider for Entity<Project> {
23452    fn completions(
23453        &self,
23454        _excerpt_id: ExcerptId,
23455        buffer: &Entity<Buffer>,
23456        buffer_position: text::Anchor,
23457        options: CompletionContext,
23458        _window: &mut Window,
23459        cx: &mut Context<Editor>,
23460    ) -> Task<Result<Vec<CompletionResponse>>> {
23461        self.update(cx, |project, cx| {
23462            let task = project.completions(buffer, buffer_position, options, cx);
23463            cx.background_spawn(task)
23464        })
23465    }
23466
23467    fn resolve_completions(
23468        &self,
23469        buffer: Entity<Buffer>,
23470        completion_indices: Vec<usize>,
23471        completions: Rc<RefCell<Box<[Completion]>>>,
23472        cx: &mut Context<Editor>,
23473    ) -> Task<Result<bool>> {
23474        self.update(cx, |project, cx| {
23475            project.lsp_store().update(cx, |lsp_store, cx| {
23476                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23477            })
23478        })
23479    }
23480
23481    fn apply_additional_edits_for_completion(
23482        &self,
23483        buffer: Entity<Buffer>,
23484        completions: Rc<RefCell<Box<[Completion]>>>,
23485        completion_index: usize,
23486        push_to_history: bool,
23487        cx: &mut Context<Editor>,
23488    ) -> Task<Result<Option<language::Transaction>>> {
23489        self.update(cx, |project, cx| {
23490            project.lsp_store().update(cx, |lsp_store, cx| {
23491                lsp_store.apply_additional_edits_for_completion(
23492                    buffer,
23493                    completions,
23494                    completion_index,
23495                    push_to_history,
23496                    cx,
23497                )
23498            })
23499        })
23500    }
23501
23502    fn is_completion_trigger(
23503        &self,
23504        buffer: &Entity<Buffer>,
23505        position: language::Anchor,
23506        text: &str,
23507        trigger_in_words: bool,
23508        menu_is_open: bool,
23509        cx: &mut Context<Editor>,
23510    ) -> bool {
23511        let mut chars = text.chars();
23512        let char = if let Some(char) = chars.next() {
23513            char
23514        } else {
23515            return false;
23516        };
23517        if chars.next().is_some() {
23518            return false;
23519        }
23520
23521        let buffer = buffer.read(cx);
23522        let snapshot = buffer.snapshot();
23523        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23524            return false;
23525        }
23526        let classifier = snapshot
23527            .char_classifier_at(position)
23528            .scope_context(Some(CharScopeContext::Completion));
23529        if trigger_in_words && classifier.is_word(char) {
23530            return true;
23531        }
23532
23533        buffer.completion_triggers().contains(text)
23534    }
23535
23536    fn show_snippets(&self) -> bool {
23537        true
23538    }
23539}
23540
23541impl SemanticsProvider for Entity<Project> {
23542    fn hover(
23543        &self,
23544        buffer: &Entity<Buffer>,
23545        position: text::Anchor,
23546        cx: &mut App,
23547    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23548        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23549    }
23550
23551    fn document_highlights(
23552        &self,
23553        buffer: &Entity<Buffer>,
23554        position: text::Anchor,
23555        cx: &mut App,
23556    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23557        Some(self.update(cx, |project, cx| {
23558            project.document_highlights(buffer, position, cx)
23559        }))
23560    }
23561
23562    fn definitions(
23563        &self,
23564        buffer: &Entity<Buffer>,
23565        position: text::Anchor,
23566        kind: GotoDefinitionKind,
23567        cx: &mut App,
23568    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23569        Some(self.update(cx, |project, cx| match kind {
23570            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23571            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23572            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23573            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23574        }))
23575    }
23576
23577    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23578        self.update(cx, |project, cx| {
23579            if project
23580                .active_debug_session(cx)
23581                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23582            {
23583                return true;
23584            }
23585
23586            buffer.update(cx, |buffer, cx| {
23587                project.any_language_server_supports_inlay_hints(buffer, cx)
23588            })
23589        })
23590    }
23591
23592    fn inline_values(
23593        &self,
23594        buffer_handle: Entity<Buffer>,
23595        range: Range<text::Anchor>,
23596        cx: &mut App,
23597    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23598        self.update(cx, |project, cx| {
23599            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23600
23601            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23602        })
23603    }
23604
23605    fn applicable_inlay_chunks(
23606        &self,
23607        buffer: &Entity<Buffer>,
23608        ranges: &[Range<text::Anchor>],
23609        cx: &mut App,
23610    ) -> Vec<Range<BufferRow>> {
23611        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23612            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23613        })
23614    }
23615
23616    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23617        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23618            lsp_store.invalidate_inlay_hints(for_buffers)
23619        });
23620    }
23621
23622    fn inlay_hints(
23623        &self,
23624        invalidate: InvalidationStrategy,
23625        buffer: Entity<Buffer>,
23626        ranges: Vec<Range<text::Anchor>>,
23627        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23628        cx: &mut App,
23629    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23630        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23631            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23632        }))
23633    }
23634
23635    fn range_for_rename(
23636        &self,
23637        buffer: &Entity<Buffer>,
23638        position: text::Anchor,
23639        cx: &mut App,
23640    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23641        Some(self.update(cx, |project, cx| {
23642            let buffer = buffer.clone();
23643            let task = project.prepare_rename(buffer.clone(), position, cx);
23644            cx.spawn(async move |_, cx| {
23645                Ok(match task.await? {
23646                    PrepareRenameResponse::Success(range) => Some(range),
23647                    PrepareRenameResponse::InvalidPosition => None,
23648                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23649                        // Fallback on using TreeSitter info to determine identifier range
23650                        buffer.read_with(cx, |buffer, _| {
23651                            let snapshot = buffer.snapshot();
23652                            let (range, kind) = snapshot.surrounding_word(position, None);
23653                            if kind != Some(CharKind::Word) {
23654                                return None;
23655                            }
23656                            Some(
23657                                snapshot.anchor_before(range.start)
23658                                    ..snapshot.anchor_after(range.end),
23659                            )
23660                        })?
23661                    }
23662                })
23663            })
23664        }))
23665    }
23666
23667    fn perform_rename(
23668        &self,
23669        buffer: &Entity<Buffer>,
23670        position: text::Anchor,
23671        new_name: String,
23672        cx: &mut App,
23673    ) -> Option<Task<Result<ProjectTransaction>>> {
23674        Some(self.update(cx, |project, cx| {
23675            project.perform_rename(buffer.clone(), position, new_name, cx)
23676        }))
23677    }
23678}
23679
23680fn consume_contiguous_rows(
23681    contiguous_row_selections: &mut Vec<Selection<Point>>,
23682    selection: &Selection<Point>,
23683    display_map: &DisplaySnapshot,
23684    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23685) -> (MultiBufferRow, MultiBufferRow) {
23686    contiguous_row_selections.push(selection.clone());
23687    let start_row = starting_row(selection, display_map);
23688    let mut end_row = ending_row(selection, display_map);
23689
23690    while let Some(next_selection) = selections.peek() {
23691        if next_selection.start.row <= end_row.0 {
23692            end_row = ending_row(next_selection, display_map);
23693            contiguous_row_selections.push(selections.next().unwrap().clone());
23694        } else {
23695            break;
23696        }
23697    }
23698    (start_row, end_row)
23699}
23700
23701fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23702    if selection.start.column > 0 {
23703        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23704    } else {
23705        MultiBufferRow(selection.start.row)
23706    }
23707}
23708
23709fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23710    if next_selection.end.column > 0 || next_selection.is_empty() {
23711        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23712    } else {
23713        MultiBufferRow(next_selection.end.row)
23714    }
23715}
23716
23717impl EditorSnapshot {
23718    pub fn remote_selections_in_range<'a>(
23719        &'a self,
23720        range: &'a Range<Anchor>,
23721        collaboration_hub: &dyn CollaborationHub,
23722        cx: &'a App,
23723    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23724        let participant_names = collaboration_hub.user_names(cx);
23725        let participant_indices = collaboration_hub.user_participant_indices(cx);
23726        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23727        let collaborators_by_replica_id = collaborators_by_peer_id
23728            .values()
23729            .map(|collaborator| (collaborator.replica_id, collaborator))
23730            .collect::<HashMap<_, _>>();
23731        self.buffer_snapshot()
23732            .selections_in_range(range, false)
23733            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23734                if replica_id == ReplicaId::AGENT {
23735                    Some(RemoteSelection {
23736                        replica_id,
23737                        selection,
23738                        cursor_shape,
23739                        line_mode,
23740                        collaborator_id: CollaboratorId::Agent,
23741                        user_name: Some("Agent".into()),
23742                        color: cx.theme().players().agent(),
23743                    })
23744                } else {
23745                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23746                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23747                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23748                    Some(RemoteSelection {
23749                        replica_id,
23750                        selection,
23751                        cursor_shape,
23752                        line_mode,
23753                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23754                        user_name,
23755                        color: if let Some(index) = participant_index {
23756                            cx.theme().players().color_for_participant(index.0)
23757                        } else {
23758                            cx.theme().players().absent()
23759                        },
23760                    })
23761                }
23762            })
23763    }
23764
23765    pub fn hunks_for_ranges(
23766        &self,
23767        ranges: impl IntoIterator<Item = Range<Point>>,
23768    ) -> Vec<MultiBufferDiffHunk> {
23769        let mut hunks = Vec::new();
23770        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23771            HashMap::default();
23772        for query_range in ranges {
23773            let query_rows =
23774                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23775            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23776                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23777            ) {
23778                // Include deleted hunks that are adjacent to the query range, because
23779                // otherwise they would be missed.
23780                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23781                if hunk.status().is_deleted() {
23782                    intersects_range |= hunk.row_range.start == query_rows.end;
23783                    intersects_range |= hunk.row_range.end == query_rows.start;
23784                }
23785                if intersects_range {
23786                    if !processed_buffer_rows
23787                        .entry(hunk.buffer_id)
23788                        .or_default()
23789                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23790                    {
23791                        continue;
23792                    }
23793                    hunks.push(hunk);
23794                }
23795            }
23796        }
23797
23798        hunks
23799    }
23800
23801    fn display_diff_hunks_for_rows<'a>(
23802        &'a self,
23803        display_rows: Range<DisplayRow>,
23804        folded_buffers: &'a HashSet<BufferId>,
23805    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23806        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23807        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23808
23809        self.buffer_snapshot()
23810            .diff_hunks_in_range(buffer_start..buffer_end)
23811            .filter_map(|hunk| {
23812                if folded_buffers.contains(&hunk.buffer_id) {
23813                    return None;
23814                }
23815
23816                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23817                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23818
23819                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23820                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23821
23822                let display_hunk = if hunk_display_start.column() != 0 {
23823                    DisplayDiffHunk::Folded {
23824                        display_row: hunk_display_start.row(),
23825                    }
23826                } else {
23827                    let mut end_row = hunk_display_end.row();
23828                    if hunk_display_end.column() > 0 {
23829                        end_row.0 += 1;
23830                    }
23831                    let is_created_file = hunk.is_created_file();
23832                    DisplayDiffHunk::Unfolded {
23833                        status: hunk.status(),
23834                        diff_base_byte_range: hunk.diff_base_byte_range,
23835                        display_row_range: hunk_display_start.row()..end_row,
23836                        multi_buffer_range: Anchor::range_in_buffer(
23837                            hunk.excerpt_id,
23838                            hunk.buffer_id,
23839                            hunk.buffer_range,
23840                        ),
23841                        is_created_file,
23842                    }
23843                };
23844
23845                Some(display_hunk)
23846            })
23847    }
23848
23849    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23850        self.display_snapshot
23851            .buffer_snapshot()
23852            .language_at(position)
23853    }
23854
23855    pub fn is_focused(&self) -> bool {
23856        self.is_focused
23857    }
23858
23859    pub fn placeholder_text(&self) -> Option<String> {
23860        self.placeholder_display_snapshot
23861            .as_ref()
23862            .map(|display_map| display_map.text())
23863    }
23864
23865    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23866        self.scroll_anchor.scroll_position(&self.display_snapshot)
23867    }
23868
23869    fn gutter_dimensions(
23870        &self,
23871        font_id: FontId,
23872        font_size: Pixels,
23873        max_line_number_width: Pixels,
23874        cx: &App,
23875    ) -> Option<GutterDimensions> {
23876        if !self.show_gutter {
23877            return None;
23878        }
23879
23880        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23881        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23882
23883        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23884            matches!(
23885                ProjectSettings::get_global(cx).git.git_gutter,
23886                GitGutterSetting::TrackedFiles
23887            )
23888        });
23889        let gutter_settings = EditorSettings::get_global(cx).gutter;
23890        let show_line_numbers = self
23891            .show_line_numbers
23892            .unwrap_or(gutter_settings.line_numbers);
23893        let line_gutter_width = if show_line_numbers {
23894            // Avoid flicker-like gutter resizes when the line number gains another digit by
23895            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23896            let min_width_for_number_on_gutter =
23897                ch_advance * gutter_settings.min_line_number_digits as f32;
23898            max_line_number_width.max(min_width_for_number_on_gutter)
23899        } else {
23900            0.0.into()
23901        };
23902
23903        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23904        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23905
23906        let git_blame_entries_width =
23907            self.git_blame_gutter_max_author_length
23908                .map(|max_author_length| {
23909                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23910                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23911
23912                    /// The number of characters to dedicate to gaps and margins.
23913                    const SPACING_WIDTH: usize = 4;
23914
23915                    let max_char_count = max_author_length.min(renderer.max_author_length())
23916                        + ::git::SHORT_SHA_LENGTH
23917                        + MAX_RELATIVE_TIMESTAMP.len()
23918                        + SPACING_WIDTH;
23919
23920                    ch_advance * max_char_count
23921                });
23922
23923        let is_singleton = self.buffer_snapshot().is_singleton();
23924
23925        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23926        left_padding += if !is_singleton {
23927            ch_width * 4.0
23928        } else if show_runnables || show_breakpoints {
23929            ch_width * 3.0
23930        } else if show_git_gutter && show_line_numbers {
23931            ch_width * 2.0
23932        } else if show_git_gutter || show_line_numbers {
23933            ch_width
23934        } else {
23935            px(0.)
23936        };
23937
23938        let shows_folds = is_singleton && gutter_settings.folds;
23939
23940        let right_padding = if shows_folds && show_line_numbers {
23941            ch_width * 4.0
23942        } else if shows_folds || (!is_singleton && show_line_numbers) {
23943            ch_width * 3.0
23944        } else if show_line_numbers {
23945            ch_width
23946        } else {
23947            px(0.)
23948        };
23949
23950        Some(GutterDimensions {
23951            left_padding,
23952            right_padding,
23953            width: line_gutter_width + left_padding + right_padding,
23954            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23955            git_blame_entries_width,
23956        })
23957    }
23958
23959    pub fn render_crease_toggle(
23960        &self,
23961        buffer_row: MultiBufferRow,
23962        row_contains_cursor: bool,
23963        editor: Entity<Editor>,
23964        window: &mut Window,
23965        cx: &mut App,
23966    ) -> Option<AnyElement> {
23967        let folded = self.is_line_folded(buffer_row);
23968        let mut is_foldable = false;
23969
23970        if let Some(crease) = self
23971            .crease_snapshot
23972            .query_row(buffer_row, self.buffer_snapshot())
23973        {
23974            is_foldable = true;
23975            match crease {
23976                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23977                    if let Some(render_toggle) = render_toggle {
23978                        let toggle_callback =
23979                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23980                                if folded {
23981                                    editor.update(cx, |editor, cx| {
23982                                        editor.fold_at(buffer_row, window, cx)
23983                                    });
23984                                } else {
23985                                    editor.update(cx, |editor, cx| {
23986                                        editor.unfold_at(buffer_row, window, cx)
23987                                    });
23988                                }
23989                            });
23990                        return Some((render_toggle)(
23991                            buffer_row,
23992                            folded,
23993                            toggle_callback,
23994                            window,
23995                            cx,
23996                        ));
23997                    }
23998                }
23999            }
24000        }
24001
24002        is_foldable |= self.starts_indent(buffer_row);
24003
24004        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24005            Some(
24006                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24007                    .toggle_state(folded)
24008                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24009                        if folded {
24010                            this.unfold_at(buffer_row, window, cx);
24011                        } else {
24012                            this.fold_at(buffer_row, window, cx);
24013                        }
24014                    }))
24015                    .into_any_element(),
24016            )
24017        } else {
24018            None
24019        }
24020    }
24021
24022    pub fn render_crease_trailer(
24023        &self,
24024        buffer_row: MultiBufferRow,
24025        window: &mut Window,
24026        cx: &mut App,
24027    ) -> Option<AnyElement> {
24028        let folded = self.is_line_folded(buffer_row);
24029        if let Crease::Inline { render_trailer, .. } = self
24030            .crease_snapshot
24031            .query_row(buffer_row, self.buffer_snapshot())?
24032        {
24033            let render_trailer = render_trailer.as_ref()?;
24034            Some(render_trailer(buffer_row, folded, window, cx))
24035        } else {
24036            None
24037        }
24038    }
24039}
24040
24041impl Deref for EditorSnapshot {
24042    type Target = DisplaySnapshot;
24043
24044    fn deref(&self) -> &Self::Target {
24045        &self.display_snapshot
24046    }
24047}
24048
24049#[derive(Clone, Debug, PartialEq, Eq)]
24050pub enum EditorEvent {
24051    InputIgnored {
24052        text: Arc<str>,
24053    },
24054    InputHandled {
24055        utf16_range_to_replace: Option<Range<isize>>,
24056        text: Arc<str>,
24057    },
24058    ExcerptsAdded {
24059        buffer: Entity<Buffer>,
24060        predecessor: ExcerptId,
24061        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24062    },
24063    ExcerptsRemoved {
24064        ids: Vec<ExcerptId>,
24065        removed_buffer_ids: Vec<BufferId>,
24066    },
24067    BufferFoldToggled {
24068        ids: Vec<ExcerptId>,
24069        folded: bool,
24070    },
24071    ExcerptsEdited {
24072        ids: Vec<ExcerptId>,
24073    },
24074    ExcerptsExpanded {
24075        ids: Vec<ExcerptId>,
24076    },
24077    BufferEdited,
24078    Edited {
24079        transaction_id: clock::Lamport,
24080    },
24081    Reparsed(BufferId),
24082    Focused,
24083    FocusedIn,
24084    Blurred,
24085    DirtyChanged,
24086    Saved,
24087    TitleChanged,
24088    SelectionsChanged {
24089        local: bool,
24090    },
24091    ScrollPositionChanged {
24092        local: bool,
24093        autoscroll: bool,
24094    },
24095    TransactionUndone {
24096        transaction_id: clock::Lamport,
24097    },
24098    TransactionBegun {
24099        transaction_id: clock::Lamport,
24100    },
24101    CursorShapeChanged,
24102    BreadcrumbsChanged,
24103    PushedToNavHistory {
24104        anchor: Anchor,
24105        is_deactivate: bool,
24106    },
24107}
24108
24109impl EventEmitter<EditorEvent> for Editor {}
24110
24111impl Focusable for Editor {
24112    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24113        self.focus_handle.clone()
24114    }
24115}
24116
24117impl Render for Editor {
24118    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24119        let settings = ThemeSettings::get_global(cx);
24120
24121        let mut text_style = match self.mode {
24122            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24123                color: cx.theme().colors().editor_foreground,
24124                font_family: settings.ui_font.family.clone(),
24125                font_features: settings.ui_font.features.clone(),
24126                font_fallbacks: settings.ui_font.fallbacks.clone(),
24127                font_size: rems(0.875).into(),
24128                font_weight: settings.ui_font.weight,
24129                line_height: relative(settings.buffer_line_height.value()),
24130                ..Default::default()
24131            },
24132            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24133                color: cx.theme().colors().editor_foreground,
24134                font_family: settings.buffer_font.family.clone(),
24135                font_features: settings.buffer_font.features.clone(),
24136                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24137                font_size: settings.buffer_font_size(cx).into(),
24138                font_weight: settings.buffer_font.weight,
24139                line_height: relative(settings.buffer_line_height.value()),
24140                ..Default::default()
24141            },
24142        };
24143        if let Some(text_style_refinement) = &self.text_style_refinement {
24144            text_style.refine(text_style_refinement)
24145        }
24146
24147        let background = match self.mode {
24148            EditorMode::SingleLine => cx.theme().system().transparent,
24149            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24150            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24151            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24152        };
24153
24154        EditorElement::new(
24155            &cx.entity(),
24156            EditorStyle {
24157                background,
24158                border: cx.theme().colors().border,
24159                local_player: cx.theme().players().local(),
24160                text: text_style,
24161                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24162                syntax: cx.theme().syntax().clone(),
24163                status: cx.theme().status().clone(),
24164                inlay_hints_style: make_inlay_hints_style(cx),
24165                edit_prediction_styles: make_suggestion_styles(cx),
24166                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24167                show_underlines: self.diagnostics_enabled(),
24168            },
24169        )
24170    }
24171}
24172
24173impl EntityInputHandler for Editor {
24174    fn text_for_range(
24175        &mut self,
24176        range_utf16: Range<usize>,
24177        adjusted_range: &mut Option<Range<usize>>,
24178        _: &mut Window,
24179        cx: &mut Context<Self>,
24180    ) -> Option<String> {
24181        let snapshot = self.buffer.read(cx).read(cx);
24182        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
24183        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
24184        if (start.0..end.0) != range_utf16 {
24185            adjusted_range.replace(start.0..end.0);
24186        }
24187        Some(snapshot.text_for_range(start..end).collect())
24188    }
24189
24190    fn selected_text_range(
24191        &mut self,
24192        ignore_disabled_input: bool,
24193        _: &mut Window,
24194        cx: &mut Context<Self>,
24195    ) -> Option<UTF16Selection> {
24196        // Prevent the IME menu from appearing when holding down an alphabetic key
24197        // while input is disabled.
24198        if !ignore_disabled_input && !self.input_enabled {
24199            return None;
24200        }
24201
24202        let selection = self
24203            .selections
24204            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
24205        let range = selection.range();
24206
24207        Some(UTF16Selection {
24208            range: range.start.0..range.end.0,
24209            reversed: selection.reversed,
24210        })
24211    }
24212
24213    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24214        let snapshot = self.buffer.read(cx).read(cx);
24215        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24216        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24217    }
24218
24219    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24220        self.clear_highlights::<InputComposition>(cx);
24221        self.ime_transaction.take();
24222    }
24223
24224    fn replace_text_in_range(
24225        &mut self,
24226        range_utf16: Option<Range<usize>>,
24227        text: &str,
24228        window: &mut Window,
24229        cx: &mut Context<Self>,
24230    ) {
24231        if !self.input_enabled {
24232            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24233            return;
24234        }
24235
24236        self.transact(window, cx, |this, window, cx| {
24237            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24238                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24239                Some(this.selection_replacement_ranges(range_utf16, cx))
24240            } else {
24241                this.marked_text_ranges(cx)
24242            };
24243
24244            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24245                let newest_selection_id = this.selections.newest_anchor().id;
24246                this.selections
24247                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24248                    .iter()
24249                    .zip(ranges_to_replace.iter())
24250                    .find_map(|(selection, range)| {
24251                        if selection.id == newest_selection_id {
24252                            Some(
24253                                (range.start.0 as isize - selection.head().0 as isize)
24254                                    ..(range.end.0 as isize - selection.head().0 as isize),
24255                            )
24256                        } else {
24257                            None
24258                        }
24259                    })
24260            });
24261
24262            cx.emit(EditorEvent::InputHandled {
24263                utf16_range_to_replace: range_to_replace,
24264                text: text.into(),
24265            });
24266
24267            if let Some(new_selected_ranges) = new_selected_ranges {
24268                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24269                    selections.select_ranges(new_selected_ranges)
24270                });
24271                this.backspace(&Default::default(), window, cx);
24272            }
24273
24274            this.handle_input(text, window, cx);
24275        });
24276
24277        if let Some(transaction) = self.ime_transaction {
24278            self.buffer.update(cx, |buffer, cx| {
24279                buffer.group_until_transaction(transaction, cx);
24280            });
24281        }
24282
24283        self.unmark_text(window, cx);
24284    }
24285
24286    fn replace_and_mark_text_in_range(
24287        &mut self,
24288        range_utf16: Option<Range<usize>>,
24289        text: &str,
24290        new_selected_range_utf16: Option<Range<usize>>,
24291        window: &mut Window,
24292        cx: &mut Context<Self>,
24293    ) {
24294        if !self.input_enabled {
24295            return;
24296        }
24297
24298        let transaction = self.transact(window, cx, |this, window, cx| {
24299            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24300                let snapshot = this.buffer.read(cx).read(cx);
24301                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24302                    for marked_range in &mut marked_ranges {
24303                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24304                        marked_range.start.0 += relative_range_utf16.start;
24305                        marked_range.start =
24306                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24307                        marked_range.end =
24308                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24309                    }
24310                }
24311                Some(marked_ranges)
24312            } else if let Some(range_utf16) = range_utf16 {
24313                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24314                Some(this.selection_replacement_ranges(range_utf16, cx))
24315            } else {
24316                None
24317            };
24318
24319            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24320                let newest_selection_id = this.selections.newest_anchor().id;
24321                this.selections
24322                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24323                    .iter()
24324                    .zip(ranges_to_replace.iter())
24325                    .find_map(|(selection, range)| {
24326                        if selection.id == newest_selection_id {
24327                            Some(
24328                                (range.start.0 as isize - selection.head().0 as isize)
24329                                    ..(range.end.0 as isize - selection.head().0 as isize),
24330                            )
24331                        } else {
24332                            None
24333                        }
24334                    })
24335            });
24336
24337            cx.emit(EditorEvent::InputHandled {
24338                utf16_range_to_replace: range_to_replace,
24339                text: text.into(),
24340            });
24341
24342            if let Some(ranges) = ranges_to_replace {
24343                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24344                    s.select_ranges(ranges)
24345                });
24346            }
24347
24348            let marked_ranges = {
24349                let snapshot = this.buffer.read(cx).read(cx);
24350                this.selections
24351                    .disjoint_anchors_arc()
24352                    .iter()
24353                    .map(|selection| {
24354                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24355                    })
24356                    .collect::<Vec<_>>()
24357            };
24358
24359            if text.is_empty() {
24360                this.unmark_text(window, cx);
24361            } else {
24362                this.highlight_text::<InputComposition>(
24363                    marked_ranges.clone(),
24364                    HighlightStyle {
24365                        underline: Some(UnderlineStyle {
24366                            thickness: px(1.),
24367                            color: None,
24368                            wavy: false,
24369                        }),
24370                        ..Default::default()
24371                    },
24372                    cx,
24373                );
24374            }
24375
24376            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24377            let use_autoclose = this.use_autoclose;
24378            let use_auto_surround = this.use_auto_surround;
24379            this.set_use_autoclose(false);
24380            this.set_use_auto_surround(false);
24381            this.handle_input(text, window, cx);
24382            this.set_use_autoclose(use_autoclose);
24383            this.set_use_auto_surround(use_auto_surround);
24384
24385            if let Some(new_selected_range) = new_selected_range_utf16 {
24386                let snapshot = this.buffer.read(cx).read(cx);
24387                let new_selected_ranges = marked_ranges
24388                    .into_iter()
24389                    .map(|marked_range| {
24390                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24391                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24392                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24393                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24394                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24395                    })
24396                    .collect::<Vec<_>>();
24397
24398                drop(snapshot);
24399                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24400                    selections.select_ranges(new_selected_ranges)
24401                });
24402            }
24403        });
24404
24405        self.ime_transaction = self.ime_transaction.or(transaction);
24406        if let Some(transaction) = self.ime_transaction {
24407            self.buffer.update(cx, |buffer, cx| {
24408                buffer.group_until_transaction(transaction, cx);
24409            });
24410        }
24411
24412        if self.text_highlights::<InputComposition>(cx).is_none() {
24413            self.ime_transaction.take();
24414        }
24415    }
24416
24417    fn bounds_for_range(
24418        &mut self,
24419        range_utf16: Range<usize>,
24420        element_bounds: gpui::Bounds<Pixels>,
24421        window: &mut Window,
24422        cx: &mut Context<Self>,
24423    ) -> Option<gpui::Bounds<Pixels>> {
24424        let text_layout_details = self.text_layout_details(window);
24425        let CharacterDimensions {
24426            em_width,
24427            em_advance,
24428            line_height,
24429        } = self.character_dimensions(window);
24430
24431        let snapshot = self.snapshot(window, cx);
24432        let scroll_position = snapshot.scroll_position();
24433        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24434
24435        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24436        let x = Pixels::from(
24437            ScrollOffset::from(
24438                snapshot.x_for_display_point(start, &text_layout_details)
24439                    + self.gutter_dimensions.full_width(),
24440            ) - scroll_left,
24441        );
24442        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24443
24444        Some(Bounds {
24445            origin: element_bounds.origin + point(x, y),
24446            size: size(em_width, line_height),
24447        })
24448    }
24449
24450    fn character_index_for_point(
24451        &mut self,
24452        point: gpui::Point<Pixels>,
24453        _window: &mut Window,
24454        _cx: &mut Context<Self>,
24455    ) -> Option<usize> {
24456        let position_map = self.last_position_map.as_ref()?;
24457        if !position_map.text_hitbox.contains(&point) {
24458            return None;
24459        }
24460        let display_point = position_map.point_for_position(point).previous_valid;
24461        let anchor = position_map
24462            .snapshot
24463            .display_point_to_anchor(display_point, Bias::Left);
24464        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24465        Some(utf16_offset.0)
24466    }
24467
24468    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24469        self.input_enabled
24470    }
24471}
24472
24473trait SelectionExt {
24474    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24475    fn spanned_rows(
24476        &self,
24477        include_end_if_at_line_start: bool,
24478        map: &DisplaySnapshot,
24479    ) -> Range<MultiBufferRow>;
24480}
24481
24482impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24483    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24484        let start = self
24485            .start
24486            .to_point(map.buffer_snapshot())
24487            .to_display_point(map);
24488        let end = self
24489            .end
24490            .to_point(map.buffer_snapshot())
24491            .to_display_point(map);
24492        if self.reversed {
24493            end..start
24494        } else {
24495            start..end
24496        }
24497    }
24498
24499    fn spanned_rows(
24500        &self,
24501        include_end_if_at_line_start: bool,
24502        map: &DisplaySnapshot,
24503    ) -> Range<MultiBufferRow> {
24504        let start = self.start.to_point(map.buffer_snapshot());
24505        let mut end = self.end.to_point(map.buffer_snapshot());
24506        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24507            end.row -= 1;
24508        }
24509
24510        let buffer_start = map.prev_line_boundary(start).0;
24511        let buffer_end = map.next_line_boundary(end).0;
24512        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24513    }
24514}
24515
24516impl<T: InvalidationRegion> InvalidationStack<T> {
24517    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24518    where
24519        S: Clone + ToOffset,
24520    {
24521        while let Some(region) = self.last() {
24522            let all_selections_inside_invalidation_ranges =
24523                if selections.len() == region.ranges().len() {
24524                    selections
24525                        .iter()
24526                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24527                        .all(|(selection, invalidation_range)| {
24528                            let head = selection.head().to_offset(buffer);
24529                            invalidation_range.start <= head && invalidation_range.end >= head
24530                        })
24531                } else {
24532                    false
24533                };
24534
24535            if all_selections_inside_invalidation_ranges {
24536                break;
24537            } else {
24538                self.pop();
24539            }
24540        }
24541    }
24542}
24543
24544impl<T> Default for InvalidationStack<T> {
24545    fn default() -> Self {
24546        Self(Default::default())
24547    }
24548}
24549
24550impl<T> Deref for InvalidationStack<T> {
24551    type Target = Vec<T>;
24552
24553    fn deref(&self) -> &Self::Target {
24554        &self.0
24555    }
24556}
24557
24558impl<T> DerefMut for InvalidationStack<T> {
24559    fn deref_mut(&mut self) -> &mut Self::Target {
24560        &mut self.0
24561    }
24562}
24563
24564impl InvalidationRegion for SnippetState {
24565    fn ranges(&self) -> &[Range<Anchor>] {
24566        &self.ranges[self.active_index]
24567    }
24568}
24569
24570fn edit_prediction_edit_text(
24571    current_snapshot: &BufferSnapshot,
24572    edits: &[(Range<Anchor>, impl AsRef<str>)],
24573    edit_preview: &EditPreview,
24574    include_deletions: bool,
24575    cx: &App,
24576) -> HighlightedText {
24577    let edits = edits
24578        .iter()
24579        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24580        .collect::<Vec<_>>();
24581
24582    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24583}
24584
24585fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24586    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24587    // Just show the raw edit text with basic styling
24588    let mut text = String::new();
24589    let mut highlights = Vec::new();
24590
24591    let insertion_highlight_style = HighlightStyle {
24592        color: Some(cx.theme().colors().text),
24593        ..Default::default()
24594    };
24595
24596    for (_, edit_text) in edits {
24597        let start_offset = text.len();
24598        text.push_str(edit_text);
24599        let end_offset = text.len();
24600
24601        if start_offset < end_offset {
24602            highlights.push((start_offset..end_offset, insertion_highlight_style));
24603        }
24604    }
24605
24606    HighlightedText {
24607        text: text.into(),
24608        highlights,
24609    }
24610}
24611
24612pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24613    match severity {
24614        lsp::DiagnosticSeverity::ERROR => colors.error,
24615        lsp::DiagnosticSeverity::WARNING => colors.warning,
24616        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24617        lsp::DiagnosticSeverity::HINT => colors.info,
24618        _ => colors.ignored,
24619    }
24620}
24621
24622pub fn styled_runs_for_code_label<'a>(
24623    label: &'a CodeLabel,
24624    syntax_theme: &'a theme::SyntaxTheme,
24625) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24626    let fade_out = HighlightStyle {
24627        fade_out: Some(0.35),
24628        ..Default::default()
24629    };
24630
24631    let mut prev_end = label.filter_range.end;
24632    label
24633        .runs
24634        .iter()
24635        .enumerate()
24636        .flat_map(move |(ix, (range, highlight_id))| {
24637            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24638                style
24639            } else {
24640                return Default::default();
24641            };
24642            let muted_style = style.highlight(fade_out);
24643
24644            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24645            if range.start >= label.filter_range.end {
24646                if range.start > prev_end {
24647                    runs.push((prev_end..range.start, fade_out));
24648                }
24649                runs.push((range.clone(), muted_style));
24650            } else if range.end <= label.filter_range.end {
24651                runs.push((range.clone(), style));
24652            } else {
24653                runs.push((range.start..label.filter_range.end, style));
24654                runs.push((label.filter_range.end..range.end, muted_style));
24655            }
24656            prev_end = cmp::max(prev_end, range.end);
24657
24658            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24659                runs.push((prev_end..label.text.len(), fade_out));
24660            }
24661
24662            runs
24663        })
24664}
24665
24666pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24667    let mut prev_index = 0;
24668    let mut prev_codepoint: Option<char> = None;
24669    text.char_indices()
24670        .chain([(text.len(), '\0')])
24671        .filter_map(move |(index, codepoint)| {
24672            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24673            let is_boundary = index == text.len()
24674                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24675                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24676            if is_boundary {
24677                let chunk = &text[prev_index..index];
24678                prev_index = index;
24679                Some(chunk)
24680            } else {
24681                None
24682            }
24683        })
24684}
24685
24686/// Given a string of text immediately before the cursor, iterates over possible
24687/// strings a snippet could match to. More precisely: returns an iterator over
24688/// suffixes of `text` created by splitting at word boundaries (before & after
24689/// every non-word character).
24690///
24691/// Shorter suffixes are returned first.
24692pub(crate) fn snippet_candidate_suffixes(
24693    text: &str,
24694    is_word_char: impl Fn(char) -> bool,
24695) -> impl std::iter::Iterator<Item = &str> {
24696    let mut prev_index = text.len();
24697    let mut prev_codepoint = None;
24698    text.char_indices()
24699        .rev()
24700        .chain([(0, '\0')])
24701        .filter_map(move |(index, codepoint)| {
24702            let prev_index = std::mem::replace(&mut prev_index, index);
24703            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24704            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
24705                None
24706            } else {
24707                let chunk = &text[prev_index..]; // go to end of string
24708                Some(chunk)
24709            }
24710        })
24711}
24712
24713pub trait RangeToAnchorExt: Sized {
24714    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24715
24716    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24717        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24718        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24719    }
24720}
24721
24722impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24723    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24724        let start_offset = self.start.to_offset(snapshot);
24725        let end_offset = self.end.to_offset(snapshot);
24726        if start_offset == end_offset {
24727            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24728        } else {
24729            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24730        }
24731    }
24732}
24733
24734pub trait RowExt {
24735    fn as_f64(&self) -> f64;
24736
24737    fn next_row(&self) -> Self;
24738
24739    fn previous_row(&self) -> Self;
24740
24741    fn minus(&self, other: Self) -> u32;
24742}
24743
24744impl RowExt for DisplayRow {
24745    fn as_f64(&self) -> f64 {
24746        self.0 as _
24747    }
24748
24749    fn next_row(&self) -> Self {
24750        Self(self.0 + 1)
24751    }
24752
24753    fn previous_row(&self) -> Self {
24754        Self(self.0.saturating_sub(1))
24755    }
24756
24757    fn minus(&self, other: Self) -> u32 {
24758        self.0 - other.0
24759    }
24760}
24761
24762impl RowExt for MultiBufferRow {
24763    fn as_f64(&self) -> f64 {
24764        self.0 as _
24765    }
24766
24767    fn next_row(&self) -> Self {
24768        Self(self.0 + 1)
24769    }
24770
24771    fn previous_row(&self) -> Self {
24772        Self(self.0.saturating_sub(1))
24773    }
24774
24775    fn minus(&self, other: Self) -> u32 {
24776        self.0 - other.0
24777    }
24778}
24779
24780trait RowRangeExt {
24781    type Row;
24782
24783    fn len(&self) -> usize;
24784
24785    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24786}
24787
24788impl RowRangeExt for Range<MultiBufferRow> {
24789    type Row = MultiBufferRow;
24790
24791    fn len(&self) -> usize {
24792        (self.end.0 - self.start.0) as usize
24793    }
24794
24795    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24796        (self.start.0..self.end.0).map(MultiBufferRow)
24797    }
24798}
24799
24800impl RowRangeExt for Range<DisplayRow> {
24801    type Row = DisplayRow;
24802
24803    fn len(&self) -> usize {
24804        (self.end.0 - self.start.0) as usize
24805    }
24806
24807    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24808        (self.start.0..self.end.0).map(DisplayRow)
24809    }
24810}
24811
24812/// If select range has more than one line, we
24813/// just point the cursor to range.start.
24814fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24815    if range.start.row == range.end.row {
24816        range
24817    } else {
24818        range.start..range.start
24819    }
24820}
24821pub struct KillRing(ClipboardItem);
24822impl Global for KillRing {}
24823
24824const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24825
24826enum BreakpointPromptEditAction {
24827    Log,
24828    Condition,
24829    HitCondition,
24830}
24831
24832struct BreakpointPromptEditor {
24833    pub(crate) prompt: Entity<Editor>,
24834    editor: WeakEntity<Editor>,
24835    breakpoint_anchor: Anchor,
24836    breakpoint: Breakpoint,
24837    edit_action: BreakpointPromptEditAction,
24838    block_ids: HashSet<CustomBlockId>,
24839    editor_margins: Arc<Mutex<EditorMargins>>,
24840    _subscriptions: Vec<Subscription>,
24841}
24842
24843impl BreakpointPromptEditor {
24844    const MAX_LINES: u8 = 4;
24845
24846    fn new(
24847        editor: WeakEntity<Editor>,
24848        breakpoint_anchor: Anchor,
24849        breakpoint: Breakpoint,
24850        edit_action: BreakpointPromptEditAction,
24851        window: &mut Window,
24852        cx: &mut Context<Self>,
24853    ) -> Self {
24854        let base_text = match edit_action {
24855            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24856            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24857            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24858        }
24859        .map(|msg| msg.to_string())
24860        .unwrap_or_default();
24861
24862        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24863        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24864
24865        let prompt = cx.new(|cx| {
24866            let mut prompt = Editor::new(
24867                EditorMode::AutoHeight {
24868                    min_lines: 1,
24869                    max_lines: Some(Self::MAX_LINES as usize),
24870                },
24871                buffer,
24872                None,
24873                window,
24874                cx,
24875            );
24876            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24877            prompt.set_show_cursor_when_unfocused(false, cx);
24878            prompt.set_placeholder_text(
24879                match edit_action {
24880                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24881                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24882                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24883                },
24884                window,
24885                cx,
24886            );
24887
24888            prompt
24889        });
24890
24891        Self {
24892            prompt,
24893            editor,
24894            breakpoint_anchor,
24895            breakpoint,
24896            edit_action,
24897            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24898            block_ids: Default::default(),
24899            _subscriptions: vec![],
24900        }
24901    }
24902
24903    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24904        self.block_ids.extend(block_ids)
24905    }
24906
24907    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24908        if let Some(editor) = self.editor.upgrade() {
24909            let message = self
24910                .prompt
24911                .read(cx)
24912                .buffer
24913                .read(cx)
24914                .as_singleton()
24915                .expect("A multi buffer in breakpoint prompt isn't possible")
24916                .read(cx)
24917                .as_rope()
24918                .to_string();
24919
24920            editor.update(cx, |editor, cx| {
24921                editor.edit_breakpoint_at_anchor(
24922                    self.breakpoint_anchor,
24923                    self.breakpoint.clone(),
24924                    match self.edit_action {
24925                        BreakpointPromptEditAction::Log => {
24926                            BreakpointEditAction::EditLogMessage(message.into())
24927                        }
24928                        BreakpointPromptEditAction::Condition => {
24929                            BreakpointEditAction::EditCondition(message.into())
24930                        }
24931                        BreakpointPromptEditAction::HitCondition => {
24932                            BreakpointEditAction::EditHitCondition(message.into())
24933                        }
24934                    },
24935                    cx,
24936                );
24937
24938                editor.remove_blocks(self.block_ids.clone(), None, cx);
24939                cx.focus_self(window);
24940            });
24941        }
24942    }
24943
24944    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24945        self.editor
24946            .update(cx, |editor, cx| {
24947                editor.remove_blocks(self.block_ids.clone(), None, cx);
24948                window.focus(&editor.focus_handle);
24949            })
24950            .log_err();
24951    }
24952
24953    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24954        let settings = ThemeSettings::get_global(cx);
24955        let text_style = TextStyle {
24956            color: if self.prompt.read(cx).read_only(cx) {
24957                cx.theme().colors().text_disabled
24958            } else {
24959                cx.theme().colors().text
24960            },
24961            font_family: settings.buffer_font.family.clone(),
24962            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24963            font_size: settings.buffer_font_size(cx).into(),
24964            font_weight: settings.buffer_font.weight,
24965            line_height: relative(settings.buffer_line_height.value()),
24966            ..Default::default()
24967        };
24968        EditorElement::new(
24969            &self.prompt,
24970            EditorStyle {
24971                background: cx.theme().colors().editor_background,
24972                local_player: cx.theme().players().local(),
24973                text: text_style,
24974                ..Default::default()
24975            },
24976        )
24977    }
24978}
24979
24980impl Render for BreakpointPromptEditor {
24981    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24982        let editor_margins = *self.editor_margins.lock();
24983        let gutter_dimensions = editor_margins.gutter;
24984        h_flex()
24985            .key_context("Editor")
24986            .bg(cx.theme().colors().editor_background)
24987            .border_y_1()
24988            .border_color(cx.theme().status().info_border)
24989            .size_full()
24990            .py(window.line_height() / 2.5)
24991            .on_action(cx.listener(Self::confirm))
24992            .on_action(cx.listener(Self::cancel))
24993            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24994            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24995    }
24996}
24997
24998impl Focusable for BreakpointPromptEditor {
24999    fn focus_handle(&self, cx: &App) -> FocusHandle {
25000        self.prompt.focus_handle(cx)
25001    }
25002}
25003
25004fn all_edits_insertions_or_deletions(
25005    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25006    snapshot: &MultiBufferSnapshot,
25007) -> bool {
25008    let mut all_insertions = true;
25009    let mut all_deletions = true;
25010
25011    for (range, new_text) in edits.iter() {
25012        let range_is_empty = range.to_offset(snapshot).is_empty();
25013        let text_is_empty = new_text.is_empty();
25014
25015        if range_is_empty != text_is_empty {
25016            if range_is_empty {
25017                all_deletions = false;
25018            } else {
25019                all_insertions = false;
25020            }
25021        } else {
25022            return false;
25023        }
25024
25025        if !all_insertions && !all_deletions {
25026            return false;
25027        }
25028    }
25029    all_insertions || all_deletions
25030}
25031
25032struct MissingEditPredictionKeybindingTooltip;
25033
25034impl Render for MissingEditPredictionKeybindingTooltip {
25035    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25036        ui::tooltip_container(cx, |container, cx| {
25037            container
25038                .flex_shrink_0()
25039                .max_w_80()
25040                .min_h(rems_from_px(124.))
25041                .justify_between()
25042                .child(
25043                    v_flex()
25044                        .flex_1()
25045                        .text_ui_sm(cx)
25046                        .child(Label::new("Conflict with Accept Keybinding"))
25047                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25048                )
25049                .child(
25050                    h_flex()
25051                        .pb_1()
25052                        .gap_1()
25053                        .items_end()
25054                        .w_full()
25055                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25056                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25057                        }))
25058                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25059                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25060                        })),
25061                )
25062        })
25063    }
25064}
25065
25066#[derive(Debug, Clone, Copy, PartialEq)]
25067pub struct LineHighlight {
25068    pub background: Background,
25069    pub border: Option<gpui::Hsla>,
25070    pub include_gutter: bool,
25071    pub type_id: Option<TypeId>,
25072}
25073
25074struct LineManipulationResult {
25075    pub new_text: String,
25076    pub line_count_before: usize,
25077    pub line_count_after: usize,
25078}
25079
25080fn render_diff_hunk_controls(
25081    row: u32,
25082    status: &DiffHunkStatus,
25083    hunk_range: Range<Anchor>,
25084    is_created_file: bool,
25085    line_height: Pixels,
25086    editor: &Entity<Editor>,
25087    _window: &mut Window,
25088    cx: &mut App,
25089) -> AnyElement {
25090    h_flex()
25091        .h(line_height)
25092        .mr_1()
25093        .gap_1()
25094        .px_0p5()
25095        .pb_1()
25096        .border_x_1()
25097        .border_b_1()
25098        .border_color(cx.theme().colors().border_variant)
25099        .rounded_b_lg()
25100        .bg(cx.theme().colors().editor_background)
25101        .gap_1()
25102        .block_mouse_except_scroll()
25103        .shadow_md()
25104        .child(if status.has_secondary_hunk() {
25105            Button::new(("stage", row as u64), "Stage")
25106                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25107                .tooltip({
25108                    let focus_handle = editor.focus_handle(cx);
25109                    move |_window, cx| {
25110                        Tooltip::for_action_in(
25111                            "Stage Hunk",
25112                            &::git::ToggleStaged,
25113                            &focus_handle,
25114                            cx,
25115                        )
25116                    }
25117                })
25118                .on_click({
25119                    let editor = editor.clone();
25120                    move |_event, _window, cx| {
25121                        editor.update(cx, |editor, cx| {
25122                            editor.stage_or_unstage_diff_hunks(
25123                                true,
25124                                vec![hunk_range.start..hunk_range.start],
25125                                cx,
25126                            );
25127                        });
25128                    }
25129                })
25130        } else {
25131            Button::new(("unstage", row as u64), "Unstage")
25132                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25133                .tooltip({
25134                    let focus_handle = editor.focus_handle(cx);
25135                    move |_window, cx| {
25136                        Tooltip::for_action_in(
25137                            "Unstage Hunk",
25138                            &::git::ToggleStaged,
25139                            &focus_handle,
25140                            cx,
25141                        )
25142                    }
25143                })
25144                .on_click({
25145                    let editor = editor.clone();
25146                    move |_event, _window, cx| {
25147                        editor.update(cx, |editor, cx| {
25148                            editor.stage_or_unstage_diff_hunks(
25149                                false,
25150                                vec![hunk_range.start..hunk_range.start],
25151                                cx,
25152                            );
25153                        });
25154                    }
25155                })
25156        })
25157        .child(
25158            Button::new(("restore", row as u64), "Restore")
25159                .tooltip({
25160                    let focus_handle = editor.focus_handle(cx);
25161                    move |_window, cx| {
25162                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25163                    }
25164                })
25165                .on_click({
25166                    let editor = editor.clone();
25167                    move |_event, window, cx| {
25168                        editor.update(cx, |editor, cx| {
25169                            let snapshot = editor.snapshot(window, cx);
25170                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25171                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25172                        });
25173                    }
25174                })
25175                .disabled(is_created_file),
25176        )
25177        .when(
25178            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25179            |el| {
25180                el.child(
25181                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25182                        .shape(IconButtonShape::Square)
25183                        .icon_size(IconSize::Small)
25184                        // .disabled(!has_multiple_hunks)
25185                        .tooltip({
25186                            let focus_handle = editor.focus_handle(cx);
25187                            move |_window, cx| {
25188                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25189                            }
25190                        })
25191                        .on_click({
25192                            let editor = editor.clone();
25193                            move |_event, window, cx| {
25194                                editor.update(cx, |editor, cx| {
25195                                    let snapshot = editor.snapshot(window, cx);
25196                                    let position =
25197                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25198                                    editor.go_to_hunk_before_or_after_position(
25199                                        &snapshot,
25200                                        position,
25201                                        Direction::Next,
25202                                        window,
25203                                        cx,
25204                                    );
25205                                    editor.expand_selected_diff_hunks(cx);
25206                                });
25207                            }
25208                        }),
25209                )
25210                .child(
25211                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25212                        .shape(IconButtonShape::Square)
25213                        .icon_size(IconSize::Small)
25214                        // .disabled(!has_multiple_hunks)
25215                        .tooltip({
25216                            let focus_handle = editor.focus_handle(cx);
25217                            move |_window, cx| {
25218                                Tooltip::for_action_in(
25219                                    "Previous Hunk",
25220                                    &GoToPreviousHunk,
25221                                    &focus_handle,
25222                                    cx,
25223                                )
25224                            }
25225                        })
25226                        .on_click({
25227                            let editor = editor.clone();
25228                            move |_event, window, cx| {
25229                                editor.update(cx, |editor, cx| {
25230                                    let snapshot = editor.snapshot(window, cx);
25231                                    let point =
25232                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25233                                    editor.go_to_hunk_before_or_after_position(
25234                                        &snapshot,
25235                                        point,
25236                                        Direction::Prev,
25237                                        window,
25238                                        cx,
25239                                    );
25240                                    editor.expand_selected_diff_hunks(cx);
25241                                });
25242                            }
25243                        }),
25244                )
25245            },
25246        )
25247        .into_any_element()
25248}
25249
25250pub fn multibuffer_context_lines(cx: &App) -> u32 {
25251    EditorSettings::try_get(cx)
25252        .map(|settings| settings.excerpt_context_lines)
25253        .unwrap_or(2)
25254        .min(32)
25255}